diff options
author | Jari Vetoniemi <jari.vetoniemi@indooratlas.com> | 2020-03-16 18:49:26 +0900 |
---|---|---|
committer | Jari Vetoniemi <jari.vetoniemi@indooratlas.com> | 2020-03-30 00:39:06 +0900 |
commit | fcbf63e62c627deae76c1b8cb8c0876c536ed811 (patch) | |
tree | 64cb17de3f41a2b6fef2368028fbd00349946994 /jni/ruby/lib/rdoc |
Fresh start
Diffstat (limited to 'jni/ruby/lib/rdoc')
175 files changed, 49476 insertions, 0 deletions
diff --git a/jni/ruby/lib/rdoc/alias.rb b/jni/ruby/lib/rdoc/alias.rb new file mode 100644 index 0000000..39d2694 --- /dev/null +++ b/jni/ruby/lib/rdoc/alias.rb @@ -0,0 +1,111 @@ +## +# Represent an alias, which is an old_name/new_name pair associated with a +# particular context +#-- +# TODO implement Alias as a proxy to a method/attribute, inheriting from +# MethodAttr + +class RDoc::Alias < RDoc::CodeObject + + ## + # Aliased method's name + + attr_reader :new_name + + alias name new_name + + ## + # Aliasee method's name + + attr_reader :old_name + + ## + # Is this an alias declared in a singleton context? + + attr_accessor :singleton + + ## + # Source file token stream + + attr_reader :text + + ## + # Creates a new Alias with a token stream of +text+ that aliases +old_name+ + # to +new_name+, has +comment+ and is a +singleton+ context. + + def initialize(text, old_name, new_name, comment, singleton = false) + super() + + @text = text + @singleton = singleton + @old_name = old_name + @new_name = new_name + self.comment = comment + end + + ## + # Order by #singleton then #new_name + + def <=>(other) + [@singleton ? 0 : 1, new_name] <=> [other.singleton ? 0 : 1, other.new_name] + end + + ## + # HTML fragment reference for this alias + + def aref + type = singleton ? 'c' : 'i' + "#alias-#{type}-#{html_name}" + end + + ## + # Full old name including namespace + + def full_old_name + @full_name || "#{parent.name}#{pretty_old_name}" + end + + ## + # HTML id-friendly version of +#new_name+. + + def html_name + CGI.escape(@new_name.gsub('-', '-2D')).gsub('%','-').sub(/^-/, '') + end + + def inspect # :nodoc: + parent_name = parent ? parent.name : '(unknown)' + "#<%s:0x%x %s.alias_method %s, %s>" % [ + self.class, object_id, + parent_name, @old_name, @new_name, + ] + end + + ## + # '::' for the alias of a singleton method/attribute, '#' for instance-level. + + def name_prefix + singleton ? '::' : '#' + end + + ## + # Old name with prefix '::' or '#'. + + def pretty_old_name + "#{singleton ? '::' : '#'}#{@old_name}" + end + + ## + # New name with prefix '::' or '#'. + + def pretty_new_name + "#{singleton ? '::' : '#'}#{@new_name}" + end + + alias pretty_name pretty_new_name + + def to_s # :nodoc: + "alias: #{self.new_name} -> #{self.pretty_old_name} in: #{parent}" + end + +end + diff --git a/jni/ruby/lib/rdoc/anon_class.rb b/jni/ruby/lib/rdoc/anon_class.rb new file mode 100644 index 0000000..c23d8e5 --- /dev/null +++ b/jni/ruby/lib/rdoc/anon_class.rb @@ -0,0 +1,10 @@ +## +# An anonymous class like: +# +# c = Class.new do end +# +# AnonClass is currently not used. + +class RDoc::AnonClass < RDoc::ClassModule +end + diff --git a/jni/ruby/lib/rdoc/any_method.rb b/jni/ruby/lib/rdoc/any_method.rb new file mode 100644 index 0000000..ae022d7 --- /dev/null +++ b/jni/ruby/lib/rdoc/any_method.rb @@ -0,0 +1,316 @@ +## +# AnyMethod is the base class for objects representing methods + +class RDoc::AnyMethod < RDoc::MethodAttr + + ## + # 2:: + # RDoc 4 + # Added calls_super + # Added parent name and class + # Added section title + # 3:: + # RDoc 4.1 + # Added is_alias_for + + MARSHAL_VERSION = 3 # :nodoc: + + ## + # Don't rename \#initialize to \::new + + attr_accessor :dont_rename_initialize + + ## + # The C function that implements this method (if it was defined in a C file) + + attr_accessor :c_function + + ## + # Different ways to call this method + + attr_reader :call_seq + + ## + # Parameters for this method + + attr_accessor :params + + ## + # If true this method uses +super+ to call a superclass version + + attr_accessor :calls_super + + include RDoc::TokenStream + + ## + # Creates a new AnyMethod with a token stream +text+ and +name+ + + def initialize text, name + super + + @c_function = nil + @dont_rename_initialize = false + @token_stream = nil + @calls_super = false + @superclass_method = nil + end + + ## + # Adds +an_alias+ as an alias for this method in +context+. + + def add_alias an_alias, context = nil + method = self.class.new an_alias.text, an_alias.new_name + + method.record_location an_alias.file + method.singleton = self.singleton + method.params = self.params + method.visibility = self.visibility + method.comment = an_alias.comment + method.is_alias_for = self + @aliases << method + context.add_method method if context + method + end + + ## + # Prefix for +aref+ is 'method'. + + def aref_prefix + 'method' + end + + ## + # The call_seq or the param_seq with method name, if there is no call_seq. + # + # Use this for displaying a method's argument lists. + + def arglists + if @call_seq then + @call_seq + elsif @params then + "#{name}#{param_seq}" + end + end + + ## + # Sets the different ways you can call this method. If an empty +call_seq+ + # is given nil is assumed. + # + # See also #param_seq + + def call_seq= call_seq + return if call_seq.empty? + + @call_seq = call_seq + end + + ## + # Loads is_alias_for from the internal name. Returns nil if the alias + # cannot be found. + + def is_alias_for # :nodoc: + case @is_alias_for + when RDoc::MethodAttr then + @is_alias_for + when Array then + return nil unless @store + + klass_name, singleton, method_name = @is_alias_for + + return nil unless klass = @store.find_class_or_module(klass_name) + + @is_alias_for = klass.find_method method_name, singleton + end + end + + ## + # Dumps this AnyMethod for use by ri. See also #marshal_load + + def marshal_dump + aliases = @aliases.map do |a| + [a.name, parse(a.comment)] + end + + is_alias_for = [ + @is_alias_for.parent.full_name, + @is_alias_for.singleton, + @is_alias_for.name + ] if @is_alias_for + + [ MARSHAL_VERSION, + @name, + full_name, + @singleton, + @visibility, + parse(@comment), + @call_seq, + @block_params, + aliases, + @params, + @file.relative_name, + @calls_super, + @parent.name, + @parent.class, + @section.title, + is_alias_for, + ] + end + + ## + # Loads this AnyMethod from +array+. For a loaded AnyMethod the following + # methods will return cached values: + # + # * #full_name + # * #parent_name + + def marshal_load array + initialize_visibility + + @dont_rename_initialize = nil + @token_stream = nil + @aliases = [] + @parent = nil + @parent_name = nil + @parent_class = nil + @section = nil + @file = nil + + version = array[0] + @name = array[1] + @full_name = array[2] + @singleton = array[3] + @visibility = array[4] + @comment = array[5] + @call_seq = array[6] + @block_params = array[7] + # 8 handled below + @params = array[9] + # 10 handled below + @calls_super = array[11] + @parent_name = array[12] + @parent_title = array[13] + @section_title = array[14] + @is_alias_for = array[15] + + array[8].each do |new_name, comment| + add_alias RDoc::Alias.new(nil, @name, new_name, comment, @singleton) + end + + @parent_name ||= if @full_name =~ /#/ then + $` + else + name = @full_name.split('::') + name.pop + name.join '::' + end + + @file = RDoc::TopLevel.new array[10] if version > 0 + end + + ## + # Method name + # + # If the method has no assigned name, it extracts it from #call_seq. + + def name + return @name if @name + + @name = + @call_seq[/^.*?\.(\w+)/, 1] || + @call_seq[/^.*?(\w+)/, 1] || + @call_seq if @call_seq + end + + ## + # A list of this method's method and yield parameters. +call-seq+ params + # are preferred over parsed method and block params. + + def param_list + if @call_seq then + params = @call_seq.split("\n").last + params = params.sub(/.*?\((.*)\)/, '\1') + params = params.sub(/(\{|do)\s*\|([^|]*)\|.*/, ',\2') + elsif @params then + params = @params.sub(/\((.*)\)/, '\1') + + params << ",#{@block_params}" if @block_params + elsif @block_params then + params = @block_params + else + return [] + end + + if @block_params then + # If this method has explicit block parameters, remove any explicit + # &block + params.sub!(/,?\s*&\w+/, '') + else + params.sub!(/\&(\w+)/, '\1') + end + + params = params.gsub(/\s+/, '').split(',').reject(&:empty?) + + params.map { |param| param.sub(/=.*/, '') } + end + + ## + # Pretty parameter list for this method. If the method's parameters were + # given by +call-seq+ it is preferred over the parsed values. + + def param_seq + if @call_seq then + params = @call_seq.split("\n").last + params = params.sub(/[^( ]+/, '') + params = params.sub(/(\|[^|]+\|)\s*\.\.\.\s*(end|\})/, '\1 \2') + elsif @params then + params = @params.gsub(/\s*\#.*/, '') + params = params.tr("\n", " ").squeeze(" ") + params = "(#{params})" unless params[0] == ?( + else + params = '' + end + + if @block_params then + # If this method has explicit block parameters, remove any explicit + # &block + params.sub!(/,?\s*&\w+/, '') + + block = @block_params.gsub(/\s*\#.*/, '') + block = block.tr("\n", " ").squeeze(" ") + if block[0] == ?( + block.sub!(/^\(/, '').sub!(/\)/, '') + end + params << " { |#{block}| ... }" + end + + params + end + + ## + # Sets the store for this method and its referenced code objects. + + def store= store + super + + @file = @store.add_file @file.full_name if @file + end + + ## + # For methods that +super+, find the superclass method that would be called. + + def superclass_method + return unless @calls_super + return @superclass_method if @superclass_method + + parent.each_ancestor do |ancestor| + if method = ancestor.method_list.find { |m| m.name == @name } then + @superclass_method = method + break + end + end + + @superclass_method + end + +end + diff --git a/jni/ruby/lib/rdoc/attr.rb b/jni/ruby/lib/rdoc/attr.rb new file mode 100644 index 0000000..960e1d1 --- /dev/null +++ b/jni/ruby/lib/rdoc/attr.rb @@ -0,0 +1,175 @@ +## +# An attribute created by \#attr, \#attr_reader, \#attr_writer or +# \#attr_accessor + +class RDoc::Attr < RDoc::MethodAttr + + ## + # 3:: + # RDoc 4 + # Added parent name and class + # Added section title + + MARSHAL_VERSION = 3 # :nodoc: + + ## + # Is the attribute readable ('R'), writable ('W') or both ('RW')? + + attr_accessor :rw + + ## + # Creates a new Attr with body +text+, +name+, read/write status +rw+ and + # +comment+. +singleton+ marks this as a class attribute. + + def initialize(text, name, rw, comment, singleton = false) + super text, name + + @rw = rw + @singleton = singleton + self.comment = comment + end + + ## + # Attributes are equal when their names, singleton and rw are identical + + def == other + self.class == other.class and + self.name == other.name and + self.rw == other.rw and + self.singleton == other.singleton + end + + ## + # Add +an_alias+ as an attribute in +context+. + + def add_alias(an_alias, context) + new_attr = self.class.new(self.text, an_alias.new_name, self.rw, + self.comment, self.singleton) + + new_attr.record_location an_alias.file + new_attr.visibility = self.visibility + new_attr.is_alias_for = self + @aliases << new_attr + context.add_attribute new_attr + new_attr + end + + ## + # The #aref prefix for attributes + + def aref_prefix + 'attribute' + end + + ## + # Attributes never call super. See RDoc::AnyMethod#calls_super + # + # An RDoc::Attr can show up in the method list in some situations (see + # Gem::ConfigFile) + + def calls_super # :nodoc: + false + end + + ## + # Returns attr_reader, attr_writer or attr_accessor as appropriate. + + def definition + case @rw + when 'RW' then 'attr_accessor' + when 'R' then 'attr_reader' + when 'W' then 'attr_writer' + end + end + + def inspect # :nodoc: + alias_for = @is_alias_for ? " (alias for #{@is_alias_for.name})" : nil + visibility = self.visibility + visibility = "forced #{visibility}" if force_documentation + "#<%s:0x%x %s %s (%s)%s>" % [ + self.class, object_id, + full_name, + rw, + visibility, + alias_for, + ] + end + + ## + # Dumps this Attr for use by ri. See also #marshal_load + + def marshal_dump + [ MARSHAL_VERSION, + @name, + full_name, + @rw, + @visibility, + parse(@comment), + singleton, + @file.relative_name, + @parent.full_name, + @parent.class, + @section.title + ] + end + + ## + # Loads this Attr from +array+. For a loaded Attr the following + # methods will return cached values: + # + # * #full_name + # * #parent_name + + def marshal_load array + initialize_visibility + + @aliases = [] + @parent = nil + @parent_name = nil + @parent_class = nil + @section = nil + @file = nil + + version = array[0] + @name = array[1] + @full_name = array[2] + @rw = array[3] + @visibility = array[4] + @comment = array[5] + @singleton = array[6] || false # MARSHAL_VERSION == 0 + # 7 handled below + @parent_name = array[8] + @parent_class = array[9] + @section_title = array[10] + + @file = RDoc::TopLevel.new array[7] if version > 1 + + @parent_name ||= @full_name.split('#', 2).first + end + + def pretty_print q # :nodoc: + q.group 2, "[#{self.class.name} #{full_name} #{rw} #{visibility}", "]" do + unless comment.empty? then + q.breakable + q.text "comment:" + q.breakable + q.pp @comment + end + end + end + + def to_s # :nodoc: + "#{definition} #{name} in: #{parent}" + end + + ## + # Attributes do not have token streams. + # + # An RDoc::Attr can show up in the method list in some situations (see + # Gem::ConfigFile) + + def token_stream # :nodoc: + end + +end + diff --git a/jni/ruby/lib/rdoc/class_module.rb b/jni/ruby/lib/rdoc/class_module.rb new file mode 100644 index 0000000..71566f0 --- /dev/null +++ b/jni/ruby/lib/rdoc/class_module.rb @@ -0,0 +1,799 @@ +## +# ClassModule is the base class for objects representing either a class or a +# module. + +class RDoc::ClassModule < RDoc::Context + + ## + # 1:: + # RDoc 3.7 + # * Added visibility, singleton and file to attributes + # * Added file to constants + # * Added file to includes + # * Added file to methods + # 2:: + # RDoc 3.13 + # * Added extends + # 3:: + # RDoc 4.0 + # * Added sections + # * Added in_files + # * Added parent name + # * Complete Constant dump + + MARSHAL_VERSION = 3 # :nodoc: + + ## + # Constants that are aliases for this class or module + + attr_accessor :constant_aliases + + ## + # Comment and the location it came from. Use #add_comment to add comments + + attr_accessor :comment_location + + attr_accessor :diagram # :nodoc: + + ## + # Class or module this constant is an alias for + + attr_accessor :is_alias_for + + ## + # Return a RDoc::ClassModule of class +class_type+ that is a copy + # of module +module+. Used to promote modules to classes. + #-- + # TODO move to RDoc::NormalClass (I think) + + def self.from_module class_type, mod + klass = class_type.new mod.name + + mod.comment_location.each do |comment, location| + klass.add_comment comment, location + end + + klass.parent = mod.parent + klass.section = mod.section + klass.viewer = mod.viewer + + klass.attributes.concat mod.attributes + klass.method_list.concat mod.method_list + klass.aliases.concat mod.aliases + klass.external_aliases.concat mod.external_aliases + klass.constants.concat mod.constants + klass.includes.concat mod.includes + klass.extends.concat mod.extends + + klass.methods_hash.update mod.methods_hash + klass.constants_hash.update mod.constants_hash + + klass.current_section = mod.current_section + klass.in_files.concat mod.in_files + klass.sections.concat mod.sections + klass.unmatched_alias_lists = mod.unmatched_alias_lists + klass.current_section = mod.current_section + klass.visibility = mod.visibility + + klass.classes_hash.update mod.classes_hash + klass.modules_hash.update mod.modules_hash + klass.metadata.update mod.metadata + + klass.document_self = mod.received_nodoc ? nil : mod.document_self + klass.document_children = mod.document_children + klass.force_documentation = mod.force_documentation + klass.done_documenting = mod.done_documenting + + # update the parent of all children + + (klass.attributes + + klass.method_list + + klass.aliases + + klass.external_aliases + + klass.constants + + klass.includes + + klass.extends + + klass.classes + + klass.modules).each do |obj| + obj.parent = klass + obj.full_name = nil + end + + klass + end + + ## + # Creates a new ClassModule with +name+ with optional +superclass+ + # + # This is a constructor for subclasses, and must never be called directly. + + def initialize(name, superclass = nil) + @constant_aliases = [] + @diagram = nil + @is_alias_for = nil + @name = name + @superclass = superclass + @comment_location = [] # [[comment, location]] + + super() + end + + ## + # Adds +comment+ to this ClassModule's list of comments at +location+. This + # method is preferred over #comment= since it allows ri data to be updated + # across multiple runs. + + def add_comment comment, location + return unless document_self + + original = comment + + comment = case comment + when RDoc::Comment then + comment.normalize + else + normalize_comment comment + end + + @comment_location.delete_if { |(_, l)| l == location } + + @comment_location << [comment, location] + + self.comment = original + end + + def add_things my_things, other_things # :nodoc: + other_things.each do |group, things| + my_things[group].each { |thing| yield false, thing } if + my_things.include? group + + things.each do |thing| + yield true, thing + end + end + end + + ## + # Ancestors list for this ClassModule: the list of included modules + # (classes will add their superclass if any). + # + # Returns the included classes or modules, not the includes + # themselves. The returned values are either String or + # RDoc::NormalModule instances (see RDoc::Include#module). + # + # The values are returned in reverse order of their inclusion, + # which is the order suitable for searching methods/attributes + # in the ancestors. The superclass, if any, comes last. + + def ancestors + includes.map { |i| i.module }.reverse + end + + def aref_prefix # :nodoc: + raise NotImplementedError, "missing aref_prefix for #{self.class}" + end + + ## + # HTML fragment reference for this module or class. See + # RDoc::NormalClass#aref and RDoc::NormalModule#aref + + def aref + "#{aref_prefix}-#{full_name}" + end + + ## + # Ancestors of this class or module only + + alias direct_ancestors ancestors + + ## + # Clears the comment. Used by the Ruby parser. + + def clear_comment + @comment = '' + end + + ## + # This method is deprecated, use #add_comment instead. + # + # Appends +comment+ to the current comment, but separated by a rule. Works + # more like <tt>+=</tt>. + + def comment= comment # :nodoc: + comment = case comment + when RDoc::Comment then + comment.normalize + else + normalize_comment comment + end + + comment = "#{@comment}\n---\n#{comment}" unless @comment.empty? + + super comment + end + + ## + # Prepares this ClassModule for use by a generator. + # + # See RDoc::Store#complete + + def complete min_visibility + update_aliases + remove_nodoc_children + update_includes + remove_invisible min_visibility + end + + ## + # Does this ClassModule or any of its methods have document_self set? + + def document_self_or_methods + document_self || method_list.any?{ |m| m.document_self } + end + + ## + # Does this class or module have a comment with content or is + # #received_nodoc true? + + def documented? + return true if @received_nodoc + return false if @comment_location.empty? + @comment_location.any? { |comment, _| not comment.empty? } + end + + ## + # Iterates the ancestors of this class or module for which an + # RDoc::ClassModule exists. + + def each_ancestor # :yields: module + return enum_for __method__ unless block_given? + + ancestors.each do |mod| + next if String === mod + next if self == mod + yield mod + end + end + + ## + # Looks for a symbol in the #ancestors. See Context#find_local_symbol. + + def find_ancestor_local_symbol symbol + each_ancestor do |m| + res = m.find_local_symbol(symbol) + return res if res + end + + nil + end + + ## + # Finds a class or module with +name+ in this namespace or its descendants + + def find_class_named name + return self if full_name == name + return self if @name == name + + @classes.values.find do |klass| + next if klass == self + klass.find_class_named name + end + end + + ## + # Return the fully qualified name of this class or module + + def full_name + @full_name ||= if RDoc::ClassModule === parent then + "#{parent.full_name}::#{@name}" + else + @name + end + end + + ## + # TODO: filter included items by #display? + + def marshal_dump # :nodoc: + attrs = attributes.sort.map do |attr| + next unless attr.display? + [ attr.name, attr.rw, + attr.visibility, attr.singleton, attr.file_name, + ] + end.compact + + method_types = methods_by_type.map do |type, visibilities| + visibilities = visibilities.map do |visibility, methods| + method_names = methods.map do |method| + next unless method.display? + [method.name, method.file_name] + end.compact + + [visibility, method_names.uniq] + end + + [type, visibilities] + end + + [ MARSHAL_VERSION, + @name, + full_name, + @superclass, + parse(@comment_location), + attrs, + constants.select { |constant| constant.display? }, + includes.map do |incl| + next unless incl.display? + [incl.name, parse(incl.comment), incl.file_name] + end.compact, + method_types, + extends.map do |ext| + next unless ext.display? + [ext.name, parse(ext.comment), ext.file_name] + end.compact, + @sections.values, + @in_files.map do |tl| + tl.relative_name + end, + parent.full_name, + parent.class, + ] + end + + def marshal_load array # :nodoc: + initialize_visibility + initialize_methods_etc + @current_section = nil + @document_self = true + @done_documenting = false + @parent = nil + @temporary_section = nil + @visibility = nil + @classes = {} + @modules = {} + + @name = array[1] + @full_name = array[2] + @superclass = array[3] + @comment = array[4] + + @comment_location = if RDoc::Markup::Document === @comment.parts.first then + @comment + else + RDoc::Markup::Document.new @comment + end + + array[5].each do |name, rw, visibility, singleton, file| + singleton ||= false + visibility ||= :public + + attr = RDoc::Attr.new nil, name, rw, nil, singleton + + add_attribute attr + attr.visibility = visibility + attr.record_location RDoc::TopLevel.new file + end + + array[6].each do |constant, comment, file| + case constant + when RDoc::Constant then + add_constant constant + else + constant = add_constant RDoc::Constant.new(constant, nil, comment) + constant.record_location RDoc::TopLevel.new file + end + end + + array[7].each do |name, comment, file| + incl = add_include RDoc::Include.new(name, comment) + incl.record_location RDoc::TopLevel.new file + end + + array[8].each do |type, visibilities| + visibilities.each do |visibility, methods| + @visibility = visibility + + methods.each do |name, file| + method = RDoc::AnyMethod.new nil, name + method.singleton = true if type == 'class' + method.record_location RDoc::TopLevel.new file + add_method method + end + end + end + + array[9].each do |name, comment, file| + ext = add_extend RDoc::Extend.new(name, comment) + ext.record_location RDoc::TopLevel.new file + end if array[9] # Support Marshal version 1 + + sections = (array[10] || []).map do |section| + [section.title, section] + end + + @sections = Hash[*sections.flatten] + @current_section = add_section nil + + @in_files = [] + + (array[11] || []).each do |filename| + record_location RDoc::TopLevel.new filename + end + + @parent_name = array[12] + @parent_class = array[13] + end + + ## + # Merges +class_module+ into this ClassModule. + # + # The data in +class_module+ is preferred over the receiver. + + def merge class_module + @parent = class_module.parent + @parent_name = class_module.parent_name + + other_document = parse class_module.comment_location + + if other_document then + document = parse @comment_location + + document = document.merge other_document + + @comment = @comment_location = document + end + + cm = class_module + other_files = cm.in_files + + merge_collections attributes, cm.attributes, other_files do |add, attr| + if add then + add_attribute attr + else + @attributes.delete attr + @methods_hash.delete attr.pretty_name + end + end + + merge_collections constants, cm.constants, other_files do |add, const| + if add then + add_constant const + else + @constants.delete const + @constants_hash.delete const.name + end + end + + merge_collections includes, cm.includes, other_files do |add, incl| + if add then + add_include incl + else + @includes.delete incl + end + end + + @includes.uniq! # clean up + + merge_collections extends, cm.extends, other_files do |add, ext| + if add then + add_extend ext + else + @extends.delete ext + end + end + + @extends.uniq! # clean up + + merge_collections method_list, cm.method_list, other_files do |add, meth| + if add then + add_method meth + else + @method_list.delete meth + @methods_hash.delete meth.pretty_name + end + end + + merge_sections cm + + self + end + + ## + # Merges collection +mine+ with +other+ preferring other. +other_files+ is + # used to help determine which items should be deleted. + # + # Yields whether the item should be added or removed (true or false) and the + # item to be added or removed. + # + # merge_collections things, other.things, other.in_files do |add, thing| + # if add then + # # add the thing + # else + # # remove the thing + # end + # end + + def merge_collections mine, other, other_files, &block # :nodoc: + my_things = mine. group_by { |thing| thing.file } + other_things = other.group_by { |thing| thing.file } + + remove_things my_things, other_files, &block + add_things my_things, other_things, &block + end + + ## + # Merges the comments in this ClassModule with the comments in the other + # ClassModule +cm+. + + def merge_sections cm # :nodoc: + my_sections = sections.group_by { |section| section.title } + other_sections = cm.sections.group_by { |section| section.title } + + other_files = cm.in_files + + remove_things my_sections, other_files do |_, section| + @sections.delete section.title + end + + other_sections.each do |group, sections| + if my_sections.include? group + my_sections[group].each do |my_section| + other_section = cm.sections_hash[group] + + my_comments = my_section.comments + other_comments = other_section.comments + + other_files = other_section.in_files + + merge_collections my_comments, other_comments, other_files do |add, comment| + if add then + my_section.add_comment comment + else + my_section.remove_comment comment + end + end + end + else + sections.each do |section| + add_section group, section.comments + end + end + end + end + + ## + # Does this object represent a module? + + def module? + false + end + + ## + # Allows overriding the initial name. + # + # Used for modules and classes that are constant aliases. + + def name= new_name + @name = new_name + end + + ## + # Parses +comment_location+ into an RDoc::Markup::Document composed of + # multiple RDoc::Markup::Documents with their file set. + + def parse comment_location + case comment_location + when String then + super + when Array then + docs = comment_location.map do |comment, location| + doc = super comment + doc.file = location + doc + end + + RDoc::Markup::Document.new(*docs) + when RDoc::Comment then + doc = super comment_location.text, comment_location.format + doc.file = comment_location.location + doc + when RDoc::Markup::Document then + return comment_location + else + raise ArgumentError, "unknown comment class #{comment_location.class}" + end + end + + ## + # Path to this class or module for use with HTML generator output. + + def path + http_url @store.rdoc.generator.class_dir + end + + ## + # Name to use to generate the url: + # modules and classes that are aliases for another + # module or class return the name of the latter. + + def name_for_path + is_alias_for ? is_alias_for.full_name : full_name + end + + ## + # Returns the classes and modules that are not constants + # aliasing another class or module. For use by formatters + # only (caches its result). + + def non_aliases + @non_aliases ||= classes_and_modules.reject { |cm| cm.is_alias_for } + end + + ## + # Updates the child modules or classes of class/module +parent+ by + # deleting the ones that have been removed from the documentation. + # + # +parent_hash+ is either <tt>parent.modules_hash</tt> or + # <tt>parent.classes_hash</tt> and +all_hash+ is ::all_modules_hash or + # ::all_classes_hash. + + def remove_nodoc_children + prefix = self.full_name + '::' + + modules_hash.each_key do |name| + full_name = prefix + name + modules_hash.delete name unless @store.modules_hash[full_name] + end + + classes_hash.each_key do |name| + full_name = prefix + name + classes_hash.delete name unless @store.classes_hash[full_name] + end + end + + def remove_things my_things, other_files # :nodoc: + my_things.delete_if do |file, things| + next false unless other_files.include? file + + things.each do |thing| + yield false, thing + end + + true + end + end + + ## + # Search record used by RDoc::Generator::JsonIndex + + def search_record + [ + name, + full_name, + full_name, + '', + path, + '', + snippet(@comment_location), + ] + end + + ## + # Sets the store for this class or module and its contained code objects. + + def store= store + super + + @attributes .each do |attr| attr.store = store end + @constants .each do |const| const.store = store end + @includes .each do |incl| incl.store = store end + @extends .each do |ext| ext.store = store end + @method_list.each do |meth| meth.store = store end + end + + ## + # Get the superclass of this class. Attempts to retrieve the superclass + # object, returns the name if it is not known. + + def superclass + @store.find_class_named(@superclass) || @superclass + end + + ## + # Set the superclass of this class to +superclass+ + + def superclass=(superclass) + raise NoMethodError, "#{full_name} is a module" if module? + @superclass = superclass + end + + def to_s # :nodoc: + if is_alias_for then + "#{self.class.name} #{self.full_name} -> #{is_alias_for}" + else + super + end + end + + ## + # 'module' or 'class' + + def type + module? ? 'module' : 'class' + end + + ## + # Updates the child modules & classes by replacing the ones that are + # aliases through a constant. + # + # The aliased module/class is replaced in the children and in + # RDoc::Store#modules_hash or RDoc::Store#classes_hash + # by a copy that has <tt>RDoc::ClassModule#is_alias_for</tt> set to + # the aliased module/class, and this copy is added to <tt>#aliases</tt> + # of the aliased module/class. + # + # Formatters can use the #non_aliases method to retrieve children that + # are not aliases, for instance to list the namespace content, since + # the aliased modules are included in the constants of the class/module, + # that are listed separately. + + def update_aliases + constants.each do |const| + next unless cm = const.is_alias_for + cm_alias = cm.dup + cm_alias.name = const.name + + # Don't move top-level aliases under Object, they look ugly there + unless RDoc::TopLevel === cm_alias.parent then + cm_alias.parent = self + cm_alias.full_name = nil # force update for new parent + end + + cm_alias.aliases.clear + cm_alias.is_alias_for = cm + + if cm.module? then + @store.modules_hash[cm_alias.full_name] = cm_alias + modules_hash[const.name] = cm_alias + else + @store.classes_hash[cm_alias.full_name] = cm_alias + classes_hash[const.name] = cm_alias + end + + cm.aliases << cm_alias + end + end + + ## + # Deletes from #includes those whose module has been removed from the + # documentation. + #-- + # FIXME: includes are not reliably removed, see _possible_bug test case + + def update_includes + includes.reject! do |include| + mod = include.module + !(String === mod) && @store.modules_hash[mod.full_name].nil? + end + + includes.uniq! + end + + ## + # Deletes from #extends those whose module has been removed from the + # documentation. + #-- + # FIXME: like update_includes, extends are not reliably removed + + def update_extends + extends.reject! do |ext| + mod = ext.module + + !(String === mod) && @store.modules_hash[mod.full_name].nil? + end + + extends.uniq! + end + +end + diff --git a/jni/ruby/lib/rdoc/code_object.rb b/jni/ruby/lib/rdoc/code_object.rb new file mode 100644 index 0000000..4620fa5 --- /dev/null +++ b/jni/ruby/lib/rdoc/code_object.rb @@ -0,0 +1,429 @@ +## +# Base class for the RDoc code tree. +# +# We contain the common stuff for contexts (which are containers) and other +# elements (methods, attributes and so on) +# +# Here's the tree of the CodeObject subclasses: +# +# * RDoc::Context +# * RDoc::TopLevel +# * RDoc::ClassModule +# * RDoc::AnonClass (never used so far) +# * RDoc::NormalClass +# * RDoc::NormalModule +# * RDoc::SingleClass +# * RDoc::MethodAttr +# * RDoc::Attr +# * RDoc::AnyMethod +# * RDoc::GhostMethod +# * RDoc::MetaMethod +# * RDoc::Alias +# * RDoc::Constant +# * RDoc::Mixin +# * RDoc::Require +# * RDoc::Include + +class RDoc::CodeObject + + include RDoc::Text + + ## + # Our comment + + attr_reader :comment + + ## + # Do we document our children? + + attr_reader :document_children + + ## + # Do we document ourselves? + + attr_reader :document_self + + ## + # Are we done documenting (ie, did we come across a :enddoc:)? + + attr_reader :done_documenting + + ## + # Which file this code object was defined in + + attr_reader :file + + ## + # Force documentation of this CodeObject + + attr_reader :force_documentation + + ## + # Line in #file where this CodeObject was defined + + attr_accessor :line + + ## + # Hash of arbitrary metadata for this CodeObject + + attr_reader :metadata + + ## + # Offset in #file where this CodeObject was defined + #-- + # TODO character or byte? + + attr_accessor :offset + + ## + # Sets the parent CodeObject + + attr_writer :parent + + ## + # Did we ever receive a +:nodoc:+ directive? + + attr_reader :received_nodoc + + ## + # Set the section this CodeObject is in + + attr_writer :section + + ## + # The RDoc::Store for this object. + + attr_reader :store + + ## + # We are the model of the code, but we know that at some point we will be + # worked on by viewers. By implementing the Viewable protocol, viewers can + # associated themselves with these objects. + + attr_accessor :viewer + + ## + # Creates a new CodeObject that will document itself and its children + + def initialize + @metadata = {} + @comment = '' + @parent = nil + @parent_name = nil # for loading + @parent_class = nil # for loading + @section = nil + @section_title = nil # for loading + @file = nil + @full_name = nil + @store = nil + @track_visibility = true + + initialize_visibility + end + + ## + # Initializes state for visibility of this CodeObject and its children. + + def initialize_visibility # :nodoc: + @document_children = true + @document_self = true + @done_documenting = false + @force_documentation = false + @received_nodoc = false + @ignored = false + @suppressed = false + @track_visibility = true + end + + ## + # Replaces our comment with +comment+, unless it is empty. + + def comment=(comment) + @comment = case comment + when NilClass then '' + when RDoc::Markup::Document then comment + when RDoc::Comment then comment.normalize + else + if comment and not comment.empty? then + normalize_comment comment + else + # HACK correct fix is to have #initialize create @comment + # with the correct encoding + if String === @comment and + Object.const_defined? :Encoding and @comment.empty? then + @comment.force_encoding comment.encoding + end + @comment + end + end + end + + ## + # Should this CodeObject be displayed in output? + # + # A code object should be displayed if: + # + # * The item didn't have a nodoc or wasn't in a container that had nodoc + # * The item wasn't ignored + # * The item has documentation and was not suppressed + + def display? + @document_self and not @ignored and + (documented? or not @suppressed) + end + + ## + # Enables or disables documentation of this CodeObject's children unless it + # has been turned off by :enddoc: + + def document_children=(document_children) + return unless @track_visibility + + @document_children = document_children unless @done_documenting + end + + ## + # Enables or disables documentation of this CodeObject unless it has been + # turned off by :enddoc:. If the argument is +nil+ it means the + # documentation is turned off by +:nodoc:+. + + def document_self=(document_self) + return unless @track_visibility + return if @done_documenting + + @document_self = document_self + @received_nodoc = true if document_self.nil? + end + + ## + # Does this object have a comment with content or is #received_nodoc true? + + def documented? + @received_nodoc or !@comment.empty? + end + + ## + # Turns documentation on/off, and turns on/off #document_self + # and #document_children. + # + # Once documentation has been turned off (by +:enddoc:+), + # the object will refuse to turn #document_self or + # #document_children on, so +:doc:+ and +:start_doc:+ directives + # will have no effect in the current file. + + def done_documenting=(value) + return unless @track_visibility + @done_documenting = value + @document_self = !value + @document_children = @document_self + end + + ## + # Yields each parent of this CodeObject. See also + # RDoc::ClassModule#each_ancestor + + def each_parent + code_object = self + + while code_object = code_object.parent do + yield code_object + end + + self + end + + ## + # File name where this CodeObject was found. + # + # See also RDoc::Context#in_files + + def file_name + return unless @file + + @file.absolute_name + end + + ## + # Force the documentation of this object unless documentation + # has been turned off by :enddoc: + #-- + # HACK untested, was assigning to an ivar + + def force_documentation=(value) + @force_documentation = value unless @done_documenting + end + + ## + # Sets the full_name overriding any computed full name. + # + # Set to +nil+ to clear RDoc's cached value + + def full_name= full_name + @full_name = full_name + end + + ## + # Use this to ignore a CodeObject and all its children until found again + # (#record_location is called). An ignored item will not be displayed in + # documentation. + # + # See github issue #55 + # + # The ignored status is temporary in order to allow implementation details + # to be hidden. At the end of processing a file RDoc allows all classes + # and modules to add new documentation to previously created classes. + # + # If a class was ignored (via stopdoc) then reopened later with additional + # documentation it should be displayed. If a class was ignored and never + # reopened it should not be displayed. The ignore flag allows this to + # occur. + + def ignore + return unless @track_visibility + + @ignored = true + + stop_doc + end + + ## + # Has this class been ignored? + # + # See also #ignore + + def ignored? + @ignored + end + + ## + # The options instance from the store this CodeObject is attached to, or a + # default options instance if the CodeObject is not attached. + # + # This is used by Text#snippet + + def options + if @store and @store.rdoc then + @store.rdoc.options + else + RDoc::Options.new + end + end + + ## + # Our parent CodeObject. The parent may be missing for classes loaded from + # legacy RI data stores. + + def parent + return @parent if @parent + return nil unless @parent_name + + if @parent_class == RDoc::TopLevel then + @parent = @store.add_file @parent_name + else + @parent = @store.find_class_or_module @parent_name + + return @parent if @parent + + begin + @parent = @store.load_class @parent_name + rescue RDoc::Store::MissingFileError + nil + end + end + end + + ## + # File name of our parent + + def parent_file_name + @parent ? @parent.base_name : '(unknown)' + end + + ## + # Name of our parent + + def parent_name + @parent ? @parent.full_name : '(unknown)' + end + + ## + # Records the RDoc::TopLevel (file) where this code object was defined + + def record_location top_level + @ignored = false + @suppressed = false + @file = top_level + end + + ## + # The section this CodeObject is in. Sections allow grouping of constants, + # attributes and methods inside a class or module. + + def section + return @section if @section + + @section = parent.add_section @section_title if parent + end + + ## + # Enable capture of documentation unless documentation has been + # turned off by :enddoc: + + def start_doc + return if @done_documenting + + @document_self = true + @document_children = true + @ignored = false + @suppressed = false + end + + ## + # Disable capture of documentation + + def stop_doc + return unless @track_visibility + + @document_self = false + @document_children = false + end + + ## + # Sets the +store+ that contains this CodeObject + + def store= store + @store = store + + return unless @track_visibility + + if :nodoc == options.visibility then + initialize_visibility + @track_visibility = false + end + end + + ## + # Use this to suppress a CodeObject and all its children until the next file + # it is seen in or documentation is discovered. A suppressed item with + # documentation will be displayed while an ignored item with documentation + # may not be displayed. + + def suppress + return unless @track_visibility + + @suppressed = true + + stop_doc + end + + ## + # Has this class been suppressed? + # + # See also #suppress + + def suppressed? + @suppressed + end + +end + diff --git a/jni/ruby/lib/rdoc/code_objects.rb b/jni/ruby/lib/rdoc/code_objects.rb new file mode 100644 index 0000000..f1a626c --- /dev/null +++ b/jni/ruby/lib/rdoc/code_objects.rb @@ -0,0 +1,5 @@ +# This file was used to load all the RDoc::CodeObject subclasses at once. Now +# autoload handles this. + +require 'rdoc' + diff --git a/jni/ruby/lib/rdoc/comment.rb b/jni/ruby/lib/rdoc/comment.rb new file mode 100644 index 0000000..33ced18 --- /dev/null +++ b/jni/ruby/lib/rdoc/comment.rb @@ -0,0 +1,229 @@ +## +# A comment holds the text comment for a RDoc::CodeObject and provides a +# unified way of cleaning it up and parsing it into an RDoc::Markup::Document. +# +# Each comment may have a different markup format set by #format=. By default +# 'rdoc' is used. The :markup: directive tells RDoc which format to use. +# +# See RDoc::Markup@Other+directives for instructions on adding an alternate +# format. + +class RDoc::Comment + + include RDoc::Text + + ## + # The format of this comment. Defaults to RDoc::Markup + + attr_reader :format + + ## + # The RDoc::TopLevel this comment was found in + + attr_accessor :location + + ## + # For duck-typing when merging classes at load time + + alias file location # :nodoc: + + ## + # The text for this comment + + attr_reader :text + + ## + # Overrides the content returned by #parse. Use when there is no #text + # source for this comment + + attr_writer :document + + ## + # Creates a new comment with +text+ that is found in the RDoc::TopLevel + # +location+. + + def initialize text = nil, location = nil + @location = location + @text = text + + @document = nil + @format = 'rdoc' + @normalized = false + end + + ## + #-- + # TODO deep copy @document + + def initialize_copy copy # :nodoc: + @text = copy.text.dup + end + + def == other # :nodoc: + self.class === other and + other.text == @text and other.location == @location + end + + ## + # Look for a 'call-seq' in the comment to override the normal parameter + # handling. The :call-seq: is indented from the baseline. All lines of the + # same indentation level and prefix are consumed. + # + # For example, all of the following will be used as the :call-seq: + # + # # :call-seq: + # # ARGF.readlines(sep=$/) -> array + # # ARGF.readlines(limit) -> array + # # ARGF.readlines(sep, limit) -> array + # # + # # ARGF.to_a(sep=$/) -> array + # # ARGF.to_a(limit) -> array + # # ARGF.to_a(sep, limit) -> array + + def extract_call_seq method + # we must handle situations like the above followed by an unindented first + # comment. The difficulty is to make sure not to match lines starting + # with ARGF at the same indent, but that are after the first description + # paragraph. + if @text =~ /^\s*:?call-seq:(.*?(?:\S).*?)^\s*$/m then + all_start, all_stop = $~.offset(0) + seq_start, seq_stop = $~.offset(1) + + # we get the following lines that start with the leading word at the + # same indent, even if they have blank lines before + if $1 =~ /(^\s*\n)+^(\s*\w+)/m then + leading = $2 # ' * ARGF' in the example above + re = %r% + \A( + (^\s*\n)+ + (^#{Regexp.escape leading}.*?\n)+ + )+ + ^\s*$ + %xm + + if @text[seq_stop..-1] =~ re then + all_stop = seq_stop + $~.offset(0).last + seq_stop = seq_stop + $~.offset(1).last + end + end + + seq = @text[seq_start..seq_stop] + seq.gsub!(/^\s*(\S|\n)/m, '\1') + @text.slice! all_start...all_stop + + method.call_seq = seq.chomp + + elsif @text.sub!(/^\s*:?call-seq:(.*?)(^\s*$|\z)/m, '') then + seq = $1 + seq.gsub!(/^\s*/, '') + method.call_seq = seq + end + + method + end + + ## + # A comment is empty if its text String is empty. + + def empty? + @text.empty? + end + + ## + # HACK dubious + + def force_encoding encoding + @text.force_encoding encoding + end + + ## + # Sets the format of this comment and resets any parsed document + + def format= format + @format = format + @document = nil + end + + def inspect # :nodoc: + location = @location ? @location.relative_name : '(unknown)' + + "#<%s:%x %s %p>" % [self.class, object_id, location, @text] + end + + ## + # Normalizes the text. See RDoc::Text#normalize_comment for details + + def normalize + return self unless @text + return self if @normalized # TODO eliminate duplicate normalization + + @text = normalize_comment @text + + @normalized = true + + self + end + + ## + # Was this text normalized? + + def normalized? # :nodoc: + @normalized + end + + ## + # Parses the comment into an RDoc::Markup::Document. The parsed document is + # cached until the text is changed. + + def parse + return @document if @document + + @document = super @text, @format + @document.file = @location + @document + end + + ## + # Removes private sections from this comment. Private sections are flush to + # the comment marker and start with <tt>--</tt> and end with <tt>++</tt>. + # For C-style comments, a private marker may not start at the opening of the + # comment. + # + # /* + # *-- + # * private + # *++ + # * public + # */ + + def remove_private + # Workaround for gsub encoding for Ruby 1.9.2 and earlier + empty = '' + empty.force_encoding @text.encoding if Object.const_defined? :Encoding + + @text = @text.gsub(%r%^\s*([#*]?)--.*?^\s*(\1)\+\+\n?%m, empty) + @text = @text.sub(%r%^\s*[#*]?--.*%m, '') + end + + ## + # Replaces this comment's text with +text+ and resets the parsed document. + # + # An error is raised if the comment contains a document but no text. + + def text= text + raise RDoc::Error, 'replacing document-only comment is not allowed' if + @text.nil? and @document + + @document = nil + @text = text + end + + ## + # Returns true if this comment is in TomDoc format. + + def tomdoc? + @format == 'tomdoc' + end + +end + diff --git a/jni/ruby/lib/rdoc/constant.rb b/jni/ruby/lib/rdoc/constant.rb new file mode 100644 index 0000000..97985cb --- /dev/null +++ b/jni/ruby/lib/rdoc/constant.rb @@ -0,0 +1,186 @@ +## +# A constant + +class RDoc::Constant < RDoc::CodeObject + + MARSHAL_VERSION = 0 # :nodoc: + + ## + # Sets the module or class this is constant is an alias for. + + attr_writer :is_alias_for + + ## + # The constant's name + + attr_accessor :name + + ## + # The constant's value + + attr_accessor :value + + ## + # The constant's visibility + + attr_accessor :visibility + + ## + # Creates a new constant with +name+, +value+ and +comment+ + + def initialize(name, value, comment) + super() + + @name = name + @value = value + + @is_alias_for = nil + @visibility = nil + + self.comment = comment + end + + ## + # Constants are ordered by name + + def <=> other + return unless self.class === other + + [parent_name, name] <=> [other.parent_name, other.name] + end + + ## + # Constants are equal when their #parent and #name is the same + + def == other + self.class == other.class and + @parent == other.parent and + @name == other.name + end + + ## + # A constant is documented if it has a comment, or is an alias + # for a documented class or module. + + def documented? + return true if super + return false unless @is_alias_for + case @is_alias_for + when String then + found = @store.find_class_or_module @is_alias_for + return false unless found + @is_alias_for = found + end + @is_alias_for.documented? + end + + ## + # Full constant name including namespace + + def full_name + @full_name ||= "#{parent_name}::#{@name}" + end + + ## + # The module or class this constant is an alias for + + def is_alias_for + case @is_alias_for + when String then + found = @store.find_class_or_module @is_alias_for + @is_alias_for = found if found + @is_alias_for + else + @is_alias_for + end + end + + def inspect # :nodoc: + "#<%s:0x%x %s::%s>" % [ + self.class, object_id, + parent_name, @name, + ] + end + + ## + # Dumps this Constant for use by ri. See also #marshal_load + + def marshal_dump + alias_name = case found = is_alias_for + when RDoc::CodeObject then found.full_name + else found + end + + [ MARSHAL_VERSION, + @name, + full_name, + @visibility, + alias_name, + parse(@comment), + @file.relative_name, + parent.name, + parent.class, + section.title, + ] + end + + ## + # Loads this Constant from +array+. For a loaded Constant the following + # methods will return cached values: + # + # * #full_name + # * #parent_name + + def marshal_load array + initialize array[1], nil, array[5] + + @full_name = array[2] + @visibility = array[3] + @is_alias_for = array[4] + # 5 handled above + # 6 handled below + @parent_name = array[7] + @parent_class = array[8] + @section_title = array[9] + + @file = RDoc::TopLevel.new array[6] + end + + ## + # Path to this constant for use with HTML generator output. + + def path + "#{@parent.path}##{@name}" + end + + def pretty_print q # :nodoc: + q.group 2, "[#{self.class.name} #{full_name}", "]" do + unless comment.empty? then + q.breakable + q.text "comment:" + q.breakable + q.pp @comment + end + end + end + + ## + # Sets the store for this class or module and its contained code objects. + + def store= store + super + + @file = @store.add_file @file.full_name if @file + end + + def to_s # :nodoc: + parent_name = parent ? parent.full_name : '(unknown)' + if is_alias_for + "constant #{parent_name}::#@name -> #{is_alias_for}" + else + "constant #{parent_name}::#@name" + end + end + +end + diff --git a/jni/ruby/lib/rdoc/context.rb b/jni/ruby/lib/rdoc/context.rb new file mode 100644 index 0000000..5eb86dd --- /dev/null +++ b/jni/ruby/lib/rdoc/context.rb @@ -0,0 +1,1211 @@ +require 'cgi' + +## +# A Context is something that can hold modules, classes, methods, attributes, +# aliases, requires, and includes. Classes, modules, and files are all +# Contexts. + +class RDoc::Context < RDoc::CodeObject + + include Comparable + + ## + # Types of methods + + TYPES = %w[class instance] + + ## + # If a context has these titles it will be sorted in this order. + + TOMDOC_TITLES = [nil, 'Public', 'Internal', 'Deprecated'] # :nodoc: + TOMDOC_TITLES_SORT = TOMDOC_TITLES.sort_by { |title| title.to_s } # :nodoc: + + ## + # Class/module aliases + + attr_reader :aliases + + ## + # All attr* methods + + attr_reader :attributes + + ## + # Block params to be used in the next MethodAttr parsed under this context + + attr_accessor :block_params + + ## + # Constants defined + + attr_reader :constants + + ## + # Sets the current documentation section of documentation + + attr_writer :current_section + + ## + # Files this context is found in + + attr_reader :in_files + + ## + # Modules this context includes + + attr_reader :includes + + ## + # Modules this context is extended with + + attr_reader :extends + + ## + # Methods defined in this context + + attr_reader :method_list + + ## + # Name of this class excluding namespace. See also full_name + + attr_reader :name + + ## + # Files this context requires + + attr_reader :requires + + ## + # Use this section for the next method, attribute or constant added. + + attr_accessor :temporary_section + + ## + # Hash <tt>old_name => [aliases]</tt>, for aliases + # that haven't (yet) been resolved to a method/attribute. + # (Not to be confused with the aliases of the context.) + + attr_accessor :unmatched_alias_lists + + ## + # Aliases that could not be resolved. + + attr_reader :external_aliases + + ## + # Current visibility of this context + + attr_accessor :visibility + + ## + # Hash of registered methods. Attributes are also registered here, + # twice if they are RW. + + attr_reader :methods_hash + + ## + # Params to be used in the next MethodAttr parsed under this context + + attr_accessor :params + + ## + # Hash of registered constants. + + attr_reader :constants_hash + + ## + # Creates an unnamed empty context with public current visibility + + def initialize + super + + @in_files = [] + + @name ||= "unknown" + @parent = nil + @visibility = :public + + @current_section = Section.new self, nil, nil + @sections = { nil => @current_section } + @temporary_section = nil + + @classes = {} + @modules = {} + + initialize_methods_etc + end + + ## + # Sets the defaults for methods and so-forth + + def initialize_methods_etc + @method_list = [] + @attributes = [] + @aliases = [] + @requires = [] + @includes = [] + @extends = [] + @constants = [] + @external_aliases = [] + + # This Hash maps a method name to a list of unmatched aliases (aliases of + # a method not yet encountered). + @unmatched_alias_lists = {} + + @methods_hash = {} + @constants_hash = {} + + @params = nil + + @store ||= nil + end + + ## + # Contexts are sorted by full_name + + def <=>(other) + return nil unless RDoc::CodeObject === other + + full_name <=> other.full_name + end + + ## + # Adds an item of type +klass+ with the given +name+ and +comment+ to the + # context. + # + # Currently only RDoc::Extend and RDoc::Include are supported. + + def add klass, name, comment + if RDoc::Extend == klass then + ext = RDoc::Extend.new name, comment + add_extend ext + elsif RDoc::Include == klass then + incl = RDoc::Include.new name, comment + add_include incl + else + raise NotImplementedError, "adding a #{klass} is not implemented" + end + end + + ## + # Adds +an_alias+ that is automatically resolved + + def add_alias an_alias + return an_alias unless @document_self + + method_attr = find_method(an_alias.old_name, an_alias.singleton) || + find_attribute(an_alias.old_name, an_alias.singleton) + + if method_attr then + method_attr.add_alias an_alias, self + else + add_to @external_aliases, an_alias + unmatched_alias_list = + @unmatched_alias_lists[an_alias.pretty_old_name] ||= [] + unmatched_alias_list.push an_alias + end + + an_alias + end + + ## + # Adds +attribute+ if not already there. If it is (as method(s) or attribute), + # updates the comment if it was empty. + # + # The attribute is registered only if it defines a new method. + # For instance, <tt>attr_reader :foo</tt> will not be registered + # if method +foo+ exists, but <tt>attr_accessor :foo</tt> will be registered + # if method +foo+ exists, but <tt>foo=</tt> does not. + + def add_attribute attribute + return attribute unless @document_self + + # mainly to check for redefinition of an attribute as a method + # TODO find a policy for 'attr_reader :foo' + 'def foo=()' + register = false + + key = nil + + if attribute.rw.index 'R' then + key = attribute.pretty_name + known = @methods_hash[key] + + if known then + known.comment = attribute.comment if known.comment.empty? + elsif registered = @methods_hash[attribute.pretty_name << '='] and + RDoc::Attr === registered then + registered.rw = 'RW' + else + @methods_hash[key] = attribute + register = true + end + end + + if attribute.rw.index 'W' then + key = attribute.pretty_name << '=' + known = @methods_hash[key] + + if known then + known.comment = attribute.comment if known.comment.empty? + elsif registered = @methods_hash[attribute.pretty_name] and + RDoc::Attr === registered then + registered.rw = 'RW' + else + @methods_hash[key] = attribute + register = true + end + end + + if register then + attribute.visibility = @visibility + add_to @attributes, attribute + resolve_aliases attribute + end + + attribute + end + + ## + # Adds a class named +given_name+ with +superclass+. + # + # Both +given_name+ and +superclass+ may contain '::', and are + # interpreted relative to the +self+ context. This allows handling correctly + # examples like these: + # class RDoc::Gauntlet < Gauntlet + # module Mod + # class Object # implies < ::Object + # class SubObject < Object # this is _not_ ::Object + # + # Given <tt>class Container::Item</tt> RDoc assumes +Container+ is a module + # unless it later sees <tt>class Container</tt>. +add_class+ automatically + # upgrades +given_name+ to a class in this case. + + def add_class class_type, given_name, superclass = '::Object' + # superclass +nil+ is passed by the C parser in the following cases: + # - registering Object in 1.8 (correct) + # - registering BasicObject in 1.9 (correct) + # - registering RubyVM in 1.9 in iseq.c (incorrect: < Object in vm.c) + # + # If we later find a superclass for a registered class with a nil + # superclass, we must honor it. + + # find the name & enclosing context + if given_name =~ /^:+(\w+)$/ then + full_name = $1 + enclosing = top_level + name = full_name.split(/:+/).last + else + full_name = child_name given_name + + if full_name =~ /^(.+)::(\w+)$/ then + name = $2 + ename = $1 + enclosing = @store.classes_hash[ename] || @store.modules_hash[ename] + # HACK: crashes in actionpack/lib/action_view/helpers/form_helper.rb (metaprogramming) + unless enclosing then + # try the given name at top level (will work for the above example) + enclosing = @store.classes_hash[given_name] || + @store.modules_hash[given_name] + return enclosing if enclosing + # not found: create the parent(s) + names = ename.split('::') + enclosing = self + names.each do |n| + enclosing = enclosing.classes_hash[n] || + enclosing.modules_hash[n] || + enclosing.add_module(RDoc::NormalModule, n) + end + end + else + name = full_name + enclosing = self + end + end + + # fix up superclass + if full_name == 'BasicObject' then + superclass = nil + elsif full_name == 'Object' then + superclass = defined?(::BasicObject) ? '::BasicObject' : nil + end + + # find the superclass full name + if superclass then + if superclass =~ /^:+/ then + superclass = $' #' + else + if superclass =~ /^(\w+):+(.+)$/ then + suffix = $2 + mod = find_module_named($1) + superclass = mod.full_name + '::' + suffix if mod + else + mod = find_module_named(superclass) + superclass = mod.full_name if mod + end + end + + # did we believe it was a module? + mod = @store.modules_hash.delete superclass + + upgrade_to_class mod, RDoc::NormalClass, mod.parent if mod + + # e.g., Object < Object + superclass = nil if superclass == full_name + end + + klass = @store.classes_hash[full_name] + + if klass then + # if TopLevel, it may not be registered in the classes: + enclosing.classes_hash[name] = klass + + # update the superclass if needed + if superclass then + existing = klass.superclass + existing = existing.full_name unless existing.is_a?(String) if existing + if existing.nil? || + (existing == 'Object' && superclass != 'Object') then + klass.superclass = superclass + end + end + else + # this is a new class + mod = @store.modules_hash.delete full_name + + if mod then + klass = upgrade_to_class mod, RDoc::NormalClass, enclosing + + klass.superclass = superclass unless superclass.nil? + else + klass = class_type.new name, superclass + + enclosing.add_class_or_module(klass, enclosing.classes_hash, + @store.classes_hash) + end + end + + klass.parent = self + + klass + end + + ## + # Adds the class or module +mod+ to the modules or + # classes Hash +self_hash+, and to +all_hash+ (either + # <tt>TopLevel::modules_hash</tt> or <tt>TopLevel::classes_hash</tt>), + # unless #done_documenting is +true+. Sets the #parent of +mod+ + # to +self+, and its #section to #current_section. Returns +mod+. + + def add_class_or_module mod, self_hash, all_hash + mod.section = current_section # TODO declaring context? something is + # wrong here... + mod.parent = self + mod.store = @store + + unless @done_documenting then + self_hash[mod.name] = mod + # this must be done AFTER adding mod to its parent, so that the full + # name is correct: + all_hash[mod.full_name] = mod + end + + mod + end + + ## + # Adds +constant+ if not already there. If it is, updates the comment, + # value and/or is_alias_for of the known constant if they were empty/nil. + + def add_constant constant + return constant unless @document_self + + # HACK: avoid duplicate 'PI' & 'E' in math.c (1.8.7 source code) + # (this is a #ifdef: should be handled by the C parser) + known = @constants_hash[constant.name] + + if known then + known.comment = constant.comment if known.comment.empty? + + known.value = constant.value if + known.value.nil? or known.value.strip.empty? + + known.is_alias_for ||= constant.is_alias_for + else + @constants_hash[constant.name] = constant + add_to @constants, constant + end + + constant + end + + ## + # Adds included module +include+ which should be an RDoc::Include + + def add_include include + add_to @includes, include + + include + end + + ## + # Adds extension module +ext+ which should be an RDoc::Extend + + def add_extend ext + add_to @extends, ext + + ext + end + + ## + # Adds +method+ if not already there. If it is (as method or attribute), + # updates the comment if it was empty. + + def add_method method + return method unless @document_self + + # HACK: avoid duplicate 'new' in io.c & struct.c (1.8.7 source code) + key = method.pretty_name + known = @methods_hash[key] + + if known then + if @store then # otherwise we are loading + known.comment = method.comment if known.comment.empty? + previously = ", previously in #{known.file}" unless + method.file == known.file + @store.rdoc.options.warn \ + "Duplicate method #{known.full_name} in #{method.file}#{previously}" + end + else + @methods_hash[key] = method + method.visibility = @visibility + add_to @method_list, method + resolve_aliases method + end + + method + end + + ## + # Adds a module named +name+. If RDoc already knows +name+ is a class then + # that class is returned instead. See also #add_class. + + def add_module(class_type, name) + mod = @classes[name] || @modules[name] + return mod if mod + + full_name = child_name name + mod = @store.modules_hash[full_name] || class_type.new(name) + + add_class_or_module mod, @modules, @store.modules_hash + end + + ## + # Adds an alias from +from+ (a class or module) to +name+ which was defined + # in +file+. + + def add_module_alias from, name, file + return from if @done_documenting + + to_name = child_name name + + # if we already know this name, don't register an alias: + # see the metaprogramming in lib/active_support/basic_object.rb, + # where we already know BasicObject is a class when we find + # BasicObject = BlankSlate + return from if @store.find_class_or_module to_name + + to = from.dup + to.name = name + to.full_name = nil + + if to.module? then + @store.modules_hash[to_name] = to + @modules[name] = to + else + @store.classes_hash[to_name] = to + @classes[name] = to + end + + # Registers a constant for this alias. The constant value and comment + # will be updated later, when the Ruby parser adds the constant + const = RDoc::Constant.new name, nil, to.comment + const.record_location file + const.is_alias_for = from + add_constant const + + to + end + + ## + # Adds +require+ to this context's top level + + def add_require(require) + return require unless @document_self + + if RDoc::TopLevel === self then + add_to @requires, require + else + parent.add_require require + end + end + + ## + # Returns a section with +title+, creating it if it doesn't already exist. + # +comment+ will be appended to the section's comment. + # + # A section with a +title+ of +nil+ will return the default section. + # + # See also RDoc::Context::Section + + def add_section title, comment = nil + if section = @sections[title] then + section.add_comment comment if comment + else + section = Section.new self, title, comment + @sections[title] = section + end + + section + end + + ## + # Adds +thing+ to the collection +array+ + + def add_to array, thing + array << thing if @document_self + + thing.parent = self + thing.store = @store if @store + thing.section = current_section + end + + ## + # Is there any content? + # + # This means any of: comment, aliases, methods, attributes, external + # aliases, require, constant. + # + # Includes and extends are also checked unless <tt>includes == false</tt>. + + def any_content(includes = true) + @any_content ||= !( + @comment.empty? && + @method_list.empty? && + @attributes.empty? && + @aliases.empty? && + @external_aliases.empty? && + @requires.empty? && + @constants.empty? + ) + @any_content || (includes && !(@includes + @extends).empty? ) + end + + ## + # Creates the full name for a child with +name+ + + def child_name name + if name =~ /^:+/ + $' #' + elsif RDoc::TopLevel === self then + name + else + "#{self.full_name}::#{name}" + end + end + + ## + # Class attributes + + def class_attributes + @class_attributes ||= attributes.select { |a| a.singleton } + end + + ## + # Class methods + + def class_method_list + @class_method_list ||= method_list.select { |a| a.singleton } + end + + ## + # Array of classes in this context + + def classes + @classes.values + end + + ## + # All classes and modules in this namespace + + def classes_and_modules + classes + modules + end + + ## + # Hash of classes keyed by class name + + def classes_hash + @classes + end + + ## + # The current documentation section that new items will be added to. If + # temporary_section is available it will be used. + + def current_section + if section = @temporary_section then + @temporary_section = nil + else + section = @current_section + end + + section + end + + ## + # Is part of this thing was defined in +file+? + + def defined_in?(file) + @in_files.include?(file) + end + + def display(method_attr) # :nodoc: + if method_attr.is_a? RDoc::Attr + "#{method_attr.definition} #{method_attr.pretty_name}" + else + "method #{method_attr.pretty_name}" + end + end + + ## + # Iterator for ancestors for duck-typing. Does nothing. See + # RDoc::ClassModule#each_ancestor. + # + # This method exists to make it easy to work with Context subclasses that + # aren't part of RDoc. + + def each_ancestor # :nodoc: + end + + ## + # Iterator for attributes + + def each_attribute # :yields: attribute + @attributes.each { |a| yield a } + end + + ## + # Iterator for classes and modules + + def each_classmodule(&block) # :yields: module + classes_and_modules.sort.each(&block) + end + + ## + # Iterator for constants + + def each_constant # :yields: constant + @constants.each {|c| yield c} + end + + ## + # Iterator for included modules + + def each_include # :yields: include + @includes.each do |i| yield i end + end + + ## + # Iterator for extension modules + + def each_extend # :yields: extend + @extends.each do |e| yield e end + end + + ## + # Iterator for methods + + def each_method # :yields: method + return enum_for __method__ unless block_given? + + @method_list.sort.each { |m| yield m } + end + + ## + # Iterator for each section's contents sorted by title. The +section+, the + # section's +constants+ and the sections +attributes+ are yielded. The + # +constants+ and +attributes+ collections are sorted. + # + # To retrieve methods in a section use #methods_by_type with the optional + # +section+ parameter. + # + # NOTE: Do not edit collections yielded by this method + + def each_section # :yields: section, constants, attributes + return enum_for __method__ unless block_given? + + constants = @constants.group_by do |constant| constant.section end + attributes = @attributes.group_by do |attribute| attribute.section end + + constants.default = [] + attributes.default = [] + + sort_sections.each do |section| + yield section, constants[section].sort, attributes[section].sort + end + end + + ## + # Finds an attribute +name+ with singleton value +singleton+. + + def find_attribute(name, singleton) + name = $1 if name =~ /^(.*)=$/ + @attributes.find { |a| a.name == name && a.singleton == singleton } + end + + ## + # Finds an attribute with +name+ in this context + + def find_attribute_named(name) + case name + when /\A#/ then + find_attribute name[1..-1], false + when /\A::/ then + find_attribute name[2..-1], true + else + @attributes.find { |a| a.name == name } + end + end + + ## + # Finds a class method with +name+ in this context + + def find_class_method_named(name) + @method_list.find { |meth| meth.singleton && meth.name == name } + end + + ## + # Finds a constant with +name+ in this context + + def find_constant_named(name) + @constants.find {|m| m.name == name} + end + + ## + # Find a module at a higher scope + + def find_enclosing_module_named(name) + parent && parent.find_module_named(name) + end + + ## + # Finds an external alias +name+ with singleton value +singleton+. + + def find_external_alias(name, singleton) + @external_aliases.find { |m| m.name == name && m.singleton == singleton } + end + + ## + # Finds an external alias with +name+ in this context + + def find_external_alias_named(name) + case name + when /\A#/ then + find_external_alias name[1..-1], false + when /\A::/ then + find_external_alias name[2..-1], true + else + @external_aliases.find { |a| a.name == name } + end + end + + ## + # Finds a file with +name+ in this context + + def find_file_named name + @store.find_file_named name + end + + ## + # Finds an instance method with +name+ in this context + + def find_instance_method_named(name) + @method_list.find { |meth| !meth.singleton && meth.name == name } + end + + ## + # Finds a method, constant, attribute, external alias, module or file + # named +symbol+ in this context. + + def find_local_symbol(symbol) + find_method_named(symbol) or + find_constant_named(symbol) or + find_attribute_named(symbol) or + find_external_alias_named(symbol) or + find_module_named(symbol) or + find_file_named(symbol) + end + + ## + # Finds a method named +name+ with singleton value +singleton+. + + def find_method(name, singleton) + @method_list.find { |m| m.name == name && m.singleton == singleton } + end + + ## + # Finds a instance or module method with +name+ in this context + + def find_method_named(name) + case name + when /\A#/ then + find_method name[1..-1], false + when /\A::/ then + find_method name[2..-1], true + else + @method_list.find { |meth| meth.name == name } + end + end + + ## + # Find a module with +name+ using ruby's scoping rules + + def find_module_named(name) + res = @modules[name] || @classes[name] + return res if res + return self if self.name == name + find_enclosing_module_named name + end + + ## + # Look up +symbol+, first as a module, then as a local symbol. + + def find_symbol(symbol) + find_symbol_module(symbol) || find_local_symbol(symbol) + end + + ## + # Look up a module named +symbol+. + + def find_symbol_module(symbol) + result = nil + + # look for a class or module 'symbol' + case symbol + when /^::/ then + result = @store.find_class_or_module symbol + when /^(\w+):+(.+)$/ + suffix = $2 + top = $1 + searched = self + while searched do + mod = searched.find_module_named(top) + break unless mod + result = @store.find_class_or_module "#{mod.full_name}::#{suffix}" + break if result || searched.is_a?(RDoc::TopLevel) + searched = searched.parent + end + else + searched = self + while searched do + result = searched.find_module_named(symbol) + break if result || searched.is_a?(RDoc::TopLevel) + searched = searched.parent + end + end + + result + end + + ## + # The full name for this context. This method is overridden by subclasses. + + def full_name + '(unknown)' + end + + ## + # Does this context and its methods and constants all have documentation? + # + # (Yes, fully documented doesn't mean everything.) + + def fully_documented? + documented? and + attributes.all? { |a| a.documented? } and + method_list.all? { |m| m.documented? } and + constants.all? { |c| c.documented? } + end + + ## + # URL for this with a +prefix+ + + def http_url(prefix) + path = name_for_path + path = path.gsub(/<<\s*(\w*)/, 'from-\1') if path =~ /<</ + path = [prefix] + path.split('::') + + File.join(*path.compact) + '.html' + end + + ## + # Instance attributes + + def instance_attributes + @instance_attributes ||= attributes.reject { |a| a.singleton } + end + + ## + # Instance methods + #-- + # TODO rename to instance_methods + + def instance_method_list + @instance_method_list ||= method_list.reject { |a| a.singleton } + end + + ## + # Breaks method_list into a nested hash by type (<tt>'class'</tt> or + # <tt>'instance'</tt>) and visibility (+:public+, +:protected+, +:private+). + # + # If +section+ is provided only methods in that RDoc::Context::Section will + # be returned. + + def methods_by_type section = nil + methods = {} + + TYPES.each do |type| + visibilities = {} + RDoc::VISIBILITIES.each do |vis| + visibilities[vis] = [] + end + + methods[type] = visibilities + end + + each_method do |method| + next if section and not method.section == section + methods[method.type][method.visibility] << method + end + + methods + end + + ## + # Yields AnyMethod and Attr entries matching the list of names in +methods+. + + def methods_matching(methods, singleton = false, &block) + (@method_list + @attributes).each do |m| + yield m if methods.include?(m.name) and m.singleton == singleton + end + + each_ancestor do |parent| + parent.methods_matching(methods, singleton, &block) + end + end + + ## + # Array of modules in this context + + def modules + @modules.values + end + + ## + # Hash of modules keyed by module name + + def modules_hash + @modules + end + + ## + # Name to use to generate the url. + # <tt>#full_name</tt> by default. + + def name_for_path + full_name + end + + ## + # Changes the visibility for new methods to +visibility+ + + def ongoing_visibility=(visibility) + @visibility = visibility + end + + ## + # Record +top_level+ as a file +self+ is in. + + def record_location(top_level) + @in_files << top_level unless @in_files.include?(top_level) + end + + ## + # Should we remove this context from the documentation? + # + # The answer is yes if: + # * #received_nodoc is +true+ + # * #any_content is +false+ (not counting includes) + # * All #includes are modules (not a string), and their module has + # <tt>#remove_from_documentation? == true</tt> + # * All classes and modules have <tt>#remove_from_documentation? == true</tt> + + def remove_from_documentation? + @remove_from_documentation ||= + @received_nodoc && + !any_content(false) && + @includes.all? { |i| !i.module.is_a?(String) && i.module.remove_from_documentation? } && + classes_and_modules.all? { |cm| cm.remove_from_documentation? } + end + + ## + # Removes methods and attributes with a visibility less than +min_visibility+. + #-- + # TODO mark the visibility of attributes in the template (if not public?) + + def remove_invisible min_visibility + return if [:private, :nodoc].include? min_visibility + remove_invisible_in @method_list, min_visibility + remove_invisible_in @attributes, min_visibility + end + + ## + # Only called when min_visibility == :public or :private + + def remove_invisible_in array, min_visibility # :nodoc: + if min_visibility == :public then + array.reject! { |e| + e.visibility != :public and not e.force_documentation + } + else + array.reject! { |e| + e.visibility == :private and not e.force_documentation + } + end + end + + ## + # Tries to resolve unmatched aliases when a method or attribute has just + # been added. + + def resolve_aliases added + # resolve any pending unmatched aliases + key = added.pretty_name + unmatched_alias_list = @unmatched_alias_lists[key] + return unless unmatched_alias_list + unmatched_alias_list.each do |unmatched_alias| + added.add_alias unmatched_alias, self + @external_aliases.delete unmatched_alias + end + @unmatched_alias_lists.delete key + end + + ## + # Returns RDoc::Context::Section objects referenced in this context for use + # in a table of contents. + + def section_contents + used_sections = {} + + each_method do |method| + next unless method.display? + + used_sections[method.section] = true + end + + # order found sections + sections = sort_sections.select do |section| + used_sections[section] + end + + # only the default section is used + return [] if + sections.length == 1 and not sections.first.title + + sections + end + + ## + # Sections in this context + + def sections + @sections.values + end + + def sections_hash # :nodoc: + @sections + end + + ## + # Sets the current section to a section with +title+. See also #add_section + + def set_current_section title, comment + @current_section = add_section title, comment + end + + ## + # Given an array +methods+ of method names, set the visibility of each to + # +visibility+ + + def set_visibility_for(methods, visibility, singleton = false) + methods_matching methods, singleton do |m| + m.visibility = visibility + end + end + + ## + # Sorts sections alphabetically (default) or in TomDoc fashion (none, + # Public, Internal, Deprecated) + + def sort_sections + titles = @sections.map { |title, _| title } + + if titles.length > 1 and + TOMDOC_TITLES_SORT == + (titles | TOMDOC_TITLES).sort_by { |title| title.to_s } then + @sections.values_at(*TOMDOC_TITLES).compact + else + @sections.sort_by { |title, _| + title.to_s + }.map { |_, section| + section + } + end + end + + def to_s # :nodoc: + "#{self.class.name} #{self.full_name}" + end + + ## + # Return the TopLevel that owns us + #-- + # FIXME we can be 'owned' by several TopLevel (see #record_location & + # #in_files) + + def top_level + return @top_level if defined? @top_level + @top_level = self + @top_level = @top_level.parent until RDoc::TopLevel === @top_level + @top_level + end + + ## + # Upgrades NormalModule +mod+ in +enclosing+ to a +class_type+ + + def upgrade_to_class mod, class_type, enclosing + enclosing.modules_hash.delete mod.name + + klass = RDoc::ClassModule.from_module class_type, mod + klass.store = @store + + # if it was there, then we keep it even if done_documenting + @store.classes_hash[mod.full_name] = klass + enclosing.classes_hash[mod.name] = klass + + klass + end + + autoload :Section, 'rdoc/context/section' + +end + diff --git a/jni/ruby/lib/rdoc/context/section.rb b/jni/ruby/lib/rdoc/context/section.rb new file mode 100644 index 0000000..580f07d --- /dev/null +++ b/jni/ruby/lib/rdoc/context/section.rb @@ -0,0 +1,238 @@ +## +# A section of documentation like: +# +# # :section: The title +# # The body +# +# Sections can be referenced multiple times and will be collapsed into a +# single section. + +class RDoc::Context::Section + + include RDoc::Text + + MARSHAL_VERSION = 0 # :nodoc: + + ## + # Section comment + + attr_reader :comment + + ## + # Section comments + + attr_reader :comments + + ## + # Context this Section lives in + + attr_reader :parent + + ## + # Section title + + attr_reader :title + + @@sequence = "SEC00000" + + ## + # Creates a new section with +title+ and +comment+ + + def initialize parent, title, comment + @parent = parent + @title = title ? title.strip : title + + @@sequence.succ! + @sequence = @@sequence.dup + + @comments = [] + + add_comment comment + end + + ## + # Sections are equal when they have the same #title + + def == other + self.class === other and @title == other.title + end + + ## + # Adds +comment+ to this section + + def add_comment comment + comment = extract_comment comment + + return if comment.empty? + + case comment + when RDoc::Comment then + @comments << comment + when RDoc::Markup::Document then + @comments.concat comment.parts + when Array then + @comments.concat comment + else + raise TypeError, "unknown comment type: #{comment.inspect}" + end + end + + ## + # Anchor reference for linking to this section + + def aref + title = @title || '[untitled]' + + CGI.escape(title).gsub('%', '-').sub(/^-/, '') + end + + ## + # Extracts the comment for this section from the original comment block. + # If the first line contains :section:, strip it and use the rest. + # Otherwise remove lines up to the line containing :section:, and look + # for those lines again at the end and remove them. This lets us write + # + # # :section: The title + # # The body + + def extract_comment comment + case comment + when Array then + comment.map do |c| + extract_comment c + end + when nil + RDoc::Comment.new '' + when RDoc::Comment then + if comment.text =~ /^#[ \t]*:section:.*\n/ then + start = $` + rest = $' + + comment.text = if start.empty? then + rest + else + rest.sub(/#{start.chomp}\Z/, '') + end + end + + comment + when RDoc::Markup::Document then + comment + else + raise TypeError, "unknown comment #{comment.inspect}" + end + end + + def inspect # :nodoc: + "#<%s:0x%x %p>" % [self.class, object_id, title] + end + + ## + # The files comments in this section come from + + def in_files + return [] if @comments.empty? + + case @comments + when Array then + @comments.map do |comment| + comment.file + end + when RDoc::Markup::Document then + @comment.parts.map do |document| + document.file + end + else + raise RDoc::Error, "BUG: unknown comment class #{@comments.class}" + end + end + + ## + # Serializes this Section. The title and parsed comment are saved, but not + # the section parent which must be restored manually. + + def marshal_dump + [ + MARSHAL_VERSION, + @title, + parse, + ] + end + + ## + # De-serializes this Section. The section parent must be restored manually. + + def marshal_load array + @parent = nil + + @title = array[1] + @comments = array[2] + end + + ## + # Parses +comment_location+ into an RDoc::Markup::Document composed of + # multiple RDoc::Markup::Documents with their file set. + + def parse + case @comments + when String then + super + when Array then + docs = @comments.map do |comment, location| + doc = super comment + doc.file = location if location + doc + end + + RDoc::Markup::Document.new(*docs) + when RDoc::Comment then + doc = super @comments.text, comments.format + doc.file = @comments.location + doc + when RDoc::Markup::Document then + return @comments + else + raise ArgumentError, "unknown comment class #{comments.class}" + end + end + + ## + # The section's title, or 'Top Section' if the title is nil. + # + # This is used by the table of contents template so the name is silly. + + def plain_html + @title || 'Top Section' + end + + ## + # Removes a comment from this section if it is from the same file as + # +comment+ + + def remove_comment comment + return if @comments.empty? + + case @comments + when Array then + @comments.delete_if do |my_comment| + my_comment.file == comment.file + end + when RDoc::Markup::Document then + @comments.parts.delete_if do |document| + document.file == comment.file.name + end + else + raise RDoc::Error, "BUG: unknown comment class #{@comments.class}" + end + end + + ## + # Section sequence number (deprecated) + + def sequence + warn "RDoc::Context::Section#sequence is deprecated, use #aref" + @sequence + end + +end + diff --git a/jni/ruby/lib/rdoc/cross_reference.rb b/jni/ruby/lib/rdoc/cross_reference.rb new file mode 100644 index 0000000..5b08d52 --- /dev/null +++ b/jni/ruby/lib/rdoc/cross_reference.rb @@ -0,0 +1,183 @@ +## +# RDoc::CrossReference is a reusable way to create cross references for names. + +class RDoc::CrossReference + + ## + # Regular expression to match class references + # + # 1. There can be a '\\' in front of text to suppress the cross-reference + # 2. There can be a '::' in front of class names to reference from the + # top-level namespace. + # 3. The method can be followed by parenthesis (not recommended) + + CLASS_REGEXP_STR = '\\\\?((?:\:{2})?[A-Z]\w*(?:\:\:\w+)*)' + + ## + # Regular expression to match method references. + # + # See CLASS_REGEXP_STR + + METHOD_REGEXP_STR = '([a-z]\w*[!?=]?|%|===|\[\]=?|<<|>>)(?:\([\w.+*/=<>-]*\))?' + + ## + # Regular expressions matching text that should potentially have + # cross-reference links generated are passed to add_special. Note that + # these expressions are meant to pick up text for which cross-references + # have been suppressed, since the suppression characters are removed by the + # code that is triggered. + + CROSSREF_REGEXP = /(?:^|\s) + ( + (?: + # A::B::C.meth + #{CLASS_REGEXP_STR}(?:[.#]|::)#{METHOD_REGEXP_STR} + + # Stand-alone method (preceded by a #) + | \\?\##{METHOD_REGEXP_STR} + + # Stand-alone method (preceded by ::) + | ::#{METHOD_REGEXP_STR} + + # A::B::C + # The stuff after CLASS_REGEXP_STR is a + # nasty hack. CLASS_REGEXP_STR unfortunately matches + # words like dog and cat (these are legal "class" + # names in Fortran 95). When a word is flagged as a + # potential cross-reference, limitations in the markup + # engine suppress other processing, such as typesetting. + # This is particularly noticeable for contractions. + # In order that words like "can't" not + # be flagged as potential cross-references, only + # flag potential class cross-references if the character + # after the cross-reference is a space, sentence + # punctuation, tag start character, or attribute + # marker. + | #{CLASS_REGEXP_STR}(?=[@\s).?!,;<\000]|\z) + + # Things that look like filenames + # The key thing is that there must be at least + # one special character (period, slash, or + # underscore). + | (?:\.\.\/)*[-\/\w]+[_\/.][-\w\/.]+ + + # Things that have markup suppressed + # Don't process things like '\<' in \<tt>, though. + # TODO: including < is a hack, not very satisfying. + | \\[^\s<] + ) + + # labels for headings + (?:@[\w+%-]+(?:\.[\w|%-]+)?)? + )/x + + ## + # Version of CROSSREF_REGEXP used when <tt>--hyperlink-all</tt> is specified. + + ALL_CROSSREF_REGEXP = / + (?:^|\s) + ( + (?: + # A::B::C.meth + #{CLASS_REGEXP_STR}(?:[.#]|::)#{METHOD_REGEXP_STR} + + # Stand-alone method + | \\?#{METHOD_REGEXP_STR} + + # A::B::C + | #{CLASS_REGEXP_STR}(?=[@\s).?!,;<\000]|\z) + + # Things that look like filenames + | (?:\.\.\/)*[-\/\w]+[_\/.][-\w\/.]+ + + # Things that have markup suppressed + | \\[^\s<] + ) + + # labels for headings + (?:@[\w+%-]+)? + )/x + + ## + # Hash of references that have been looked-up to their replacements + + attr_accessor :seen + + ## + # Allows cross-references to be created based on the given +context+ + # (RDoc::Context). + + def initialize context + @context = context + @store = context.store + + @seen = {} + end + + ## + # Returns a reference to +name+. + # + # If the reference is found and +name+ is not documented +text+ will be + # returned. If +name+ is escaped +name+ is returned. If +name+ is not + # found +text+ is returned. + + def resolve name, text + return @seen[name] if @seen.include? name + + if /#{CLASS_REGEXP_STR}([.#]|::)#{METHOD_REGEXP_STR}/o =~ name then + type = $2 + type = '' if type == '.' # will find either #method or ::method + method = "#{type}#{$3}" + container = @context.find_symbol_module($1) + elsif /^([.#]|::)#{METHOD_REGEXP_STR}/o =~ name then + type = $1 + type = '' if type == '.' + method = "#{type}#{$2}" + container = @context + else + container = nil + end + + if container then + ref = container.find_local_symbol method + + unless ref || RDoc::TopLevel === container then + ref = container.find_ancestor_local_symbol method + end + end + + ref = case name + when /^\\(#{CLASS_REGEXP_STR})$/o then + @context.find_symbol $1 + else + @context.find_symbol name + end unless ref + + # Try a page name + ref = @store.page name if not ref and name =~ /^\w+$/ + + ref = nil if RDoc::Alias === ref # external alias, can't link to it + + out = if name == '\\' then + name + elsif name =~ /^\\/ then + # we remove the \ only in front of what we know: + # other backslashes are treated later, only outside of <tt> + ref ? $' : name + elsif ref then + if ref.display? then + ref + else + text + end + else + text + end + + @seen[name] = out + + out + end + +end + diff --git a/jni/ruby/lib/rdoc/encoding.rb b/jni/ruby/lib/rdoc/encoding.rb new file mode 100644 index 0000000..b3515a4 --- /dev/null +++ b/jni/ruby/lib/rdoc/encoding.rb @@ -0,0 +1,99 @@ +# coding: US-ASCII + +## +# This class is a wrapper around File IO and Encoding that helps RDoc load +# files and convert them to the correct encoding. + +module RDoc::Encoding + + ## + # Reads the contents of +filename+ and handles any encoding directives in + # the file. + # + # The content will be converted to the +encoding+. If the file cannot be + # converted a warning will be printed and nil will be returned. + # + # If +force_transcode+ is true the document will be transcoded and any + # unknown character in the target encoding will be replaced with '?' + + def self.read_file filename, encoding, force_transcode = false + content = open filename, "rb" do |f| f.read end + content.gsub!("\r\n", "\n") if RUBY_PLATFORM =~ /mswin|mingw/ + + utf8 = content.sub!(/\A\xef\xbb\xbf/, '') + + RDoc::Encoding.set_encoding content + + if Object.const_defined? :Encoding then + begin + encoding ||= Encoding.default_external + orig_encoding = content.encoding + + if not orig_encoding.ascii_compatible? then + content.encode! encoding + elsif utf8 then + content.force_encoding Encoding::UTF_8 + content.encode! encoding + else + # assume the content is in our output encoding + content.force_encoding encoding + end + + unless content.valid_encoding? then + # revert and try to transcode + content.force_encoding orig_encoding + content.encode! encoding + end + + unless content.valid_encoding? then + warn "unable to convert #{filename} to #{encoding}, skipping" + content = nil + end + rescue Encoding::InvalidByteSequenceError, + Encoding::UndefinedConversionError => e + if force_transcode then + content.force_encoding orig_encoding + content.encode!(encoding, + :invalid => :replace, :undef => :replace, + :replace => '?') + return content + else + warn "unable to convert #{e.message} for #{filename}, skipping" + return nil + end + end + end + + content + rescue ArgumentError => e + raise unless e.message =~ /unknown encoding name - (.*)/ + warn "unknown encoding name \"#{$1}\" for #{filename}, skipping" + nil + rescue Errno::EISDIR, Errno::ENOENT + nil + end + + ## + # Sets the encoding of +string+ based on the magic comment + + def self.set_encoding string + string =~ /\A(?:#!.*\n)?(.*\n)/ + + first_line = $1 + + name = case first_line + when /^<\?xml[^?]*encoding=(["'])(.*?)\1/ then $2 + when /\b(?:en)?coding[=:]\s*([^\s;]+)/i then $1 + else return + end + + string.sub! first_line, '' + + return unless Object.const_defined? :Encoding + + enc = Encoding.find name + string.force_encoding enc if enc + end + +end + diff --git a/jni/ruby/lib/rdoc/erb_partial.rb b/jni/ruby/lib/rdoc/erb_partial.rb new file mode 100644 index 0000000..910d1e0 --- /dev/null +++ b/jni/ruby/lib/rdoc/erb_partial.rb @@ -0,0 +1,18 @@ +## +# Allows an ERB template to be rendered in the context (binding) of an +# existing ERB template evaluation. + +class RDoc::ERBPartial < ERB + + ## + # Overrides +compiler+ startup to set the +eoutvar+ to an empty string only + # if it isn't already set. + + def set_eoutvar compiler, eoutvar = '_erbout' + super + + compiler.pre_cmd = ["#{eoutvar} ||= ''"] + end + +end + diff --git a/jni/ruby/lib/rdoc/erbio.rb b/jni/ruby/lib/rdoc/erbio.rb new file mode 100644 index 0000000..04a89fb --- /dev/null +++ b/jni/ruby/lib/rdoc/erbio.rb @@ -0,0 +1,37 @@ +require 'erb' + +## +# A subclass of ERB that writes directly to an IO. Credit to Aaron Patterson +# and Masatoshi SEKI. +# +# To use: +# +# erbio = RDoc::ERBIO.new '<%= "hello world" %>', nil, nil +# +# open 'hello.txt', 'w' do |io| +# erbio.result binding +# end +# +# Note that binding must enclose the io you wish to output on. + +class RDoc::ERBIO < ERB + + ## + # Defaults +eoutvar+ to 'io', otherwise is identical to ERB's initialize + + def initialize str, safe_level = nil, trim_mode = nil, eoutvar = 'io' + super + end + + ## + # Instructs +compiler+ how to write to +io_variable+ + + def set_eoutvar compiler, io_variable + compiler.put_cmd = "#{io_variable}.write" + compiler.insert_cmd = "#{io_variable}.write" + compiler.pre_cmd = [] + compiler.post_cmd = [] + end + +end + diff --git a/jni/ruby/lib/rdoc/extend.rb b/jni/ruby/lib/rdoc/extend.rb new file mode 100644 index 0000000..efa2c69 --- /dev/null +++ b/jni/ruby/lib/rdoc/extend.rb @@ -0,0 +1,9 @@ +## +# A Module extension to a class with \#extend +# +# RDoc::Extend.new 'Enumerable', 'comment ...' + +class RDoc::Extend < RDoc::Mixin + +end + diff --git a/jni/ruby/lib/rdoc/generator.rb b/jni/ruby/lib/rdoc/generator.rb new file mode 100644 index 0000000..7d3989d --- /dev/null +++ b/jni/ruby/lib/rdoc/generator.rb @@ -0,0 +1,51 @@ +## +# RDoc uses generators to turn parsed source code in the form of an +# RDoc::CodeObject tree into some form of output. RDoc comes with the HTML +# generator RDoc::Generator::Darkfish and an ri data generator +# RDoc::Generator::RI. +# +# == Registering a Generator +# +# Generators are registered by calling RDoc::RDoc.add_generator with the class +# of the generator: +# +# class My::Awesome::Generator +# RDoc::RDoc.add_generator self +# end +# +# == Adding Options to +rdoc+ +# +# Before option processing in +rdoc+, RDoc::Options will call ::setup_options +# on the generator class with an RDoc::Options instance. The generator can +# use RDoc::Options#option_parser to add command-line options to the +rdoc+ +# tool. See RDoc::Options@Custom+Options for an example and see OptionParser +# for details on how to add options. +# +# You can extend the RDoc::Options instance with additional accessors for your +# generator. +# +# == Generator Instantiation +# +# After parsing, RDoc::RDoc will instantiate a generator by calling +# #initialize with an RDoc::Store instance and an RDoc::Options instance. +# +# The RDoc::Store instance holds documentation for parsed source code. In +# RDoc 3 and earlier the RDoc::TopLevel class held this data. When upgrading +# a generator from RDoc 3 and earlier you should only need to replace +# RDoc::TopLevel with the store instance. +# +# RDoc will then call #generate on the generator instance. You can use the +# various methods on RDoc::Store and in the RDoc::CodeObject tree to create +# your desired output format. + +module RDoc::Generator + + autoload :Markup, 'rdoc/generator/markup' + + autoload :Darkfish, 'rdoc/generator/darkfish' + autoload :JsonIndex, 'rdoc/generator/json_index' + autoload :RI, 'rdoc/generator/ri' + autoload :POT, 'rdoc/generator/pot' + +end + diff --git a/jni/ruby/lib/rdoc/generator/darkfish.rb b/jni/ruby/lib/rdoc/generator/darkfish.rb new file mode 100644 index 0000000..0240404 --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/darkfish.rb @@ -0,0 +1,760 @@ +# -*- mode: ruby; ruby-indent-level: 2; tab-width: 2 -*- + +require 'erb' +require 'fileutils' +require 'pathname' +require 'rdoc/generator/markup' + +## +# Darkfish RDoc HTML Generator +# +# $Id: darkfish.rb 52 2009-01-07 02:08:11Z deveiant $ +# +# == Author/s +# * Michael Granger (ged@FaerieMUD.org) +# +# == Contributors +# * Mahlon E. Smith (mahlon@martini.nu) +# * Eric Hodel (drbrain@segment7.net) +# +# == License +# +# Copyright (c) 2007, 2008, Michael Granger. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the author/s, nor the names of the project's +# contributors may be used to endorse or promote products derived from this +# software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# == Attributions +# +# Darkfish uses the {Silk Icons}[http://www.famfamfam.com/lab/icons/silk/] set +# by Mark James. + +class RDoc::Generator::Darkfish + + RDoc::RDoc.add_generator self + + include ERB::Util + + ## + # Stylesheets, fonts, etc. that are included in RDoc. + + BUILTIN_STYLE_ITEMS = # :nodoc: + %w[ + css/fonts.css + fonts/Lato-Light.ttf + fonts/Lato-LightItalic.ttf + fonts/Lato-Regular.ttf + fonts/Lato-RegularItalic.ttf + fonts/SourceCodePro-Bold.ttf + fonts/SourceCodePro-Regular.ttf + css/rdoc.css + ] + + ## + # Path to this file's parent directory. Used to find templates and other + # resources. + + GENERATOR_DIR = File.join 'rdoc', 'generator' + + ## + # Release Version + + VERSION = '3' + + ## + # Description of this generator + + DESCRIPTION = 'HTML generator, written by Michael Granger' + + ## + # The relative path to style sheets and javascript. By default this is set + # the same as the rel_prefix. + + attr_accessor :asset_rel_path + + ## + # The path to generate files into, combined with <tt>--op</tt> from the + # options for a full path. + + attr_reader :base_dir + + ## + # Classes and modules to be used by this generator, not necessarily + # displayed. See also #modsort + + attr_reader :classes + + ## + # No files will be written when dry_run is true. + + attr_accessor :dry_run + + ## + # When false the generate methods return a String instead of writing to a + # file. The default is true. + + attr_accessor :file_output + + ## + # Files to be displayed by this generator + + attr_reader :files + + ## + # The JSON index generator for this Darkfish generator + + attr_reader :json_index + + ## + # Methods to be displayed by this generator + + attr_reader :methods + + ## + # Sorted list of classes and modules to be displayed by this generator + + attr_reader :modsort + + ## + # The RDoc::Store that is the source of the generated content + + attr_reader :store + + ## + # The directory where the template files live + + attr_reader :template_dir # :nodoc: + + ## + # The output directory + + attr_reader :outputdir + + ## + # Initialize a few instance variables before we start + + def initialize store, options + @store = store + @options = options + + @asset_rel_path = '' + @base_dir = Pathname.pwd.expand_path + @dry_run = @options.dry_run + @file_output = true + @template_dir = Pathname.new options.template_dir + @template_cache = {} + + @classes = nil + @context = nil + @files = nil + @methods = nil + @modsort = nil + + @json_index = RDoc::Generator::JsonIndex.new self, options + end + + ## + # Output progress information if debugging is enabled + + def debug_msg *msg + return unless $DEBUG_RDOC + $stderr.puts(*msg) + end + + ## + # Directory where generated class HTML files live relative to the output + # dir. + + def class_dir + nil + end + + ## + # Directory where generated class HTML files live relative to the output + # dir. + + def file_dir + nil + end + + ## + # Create the directories the generated docs will live in if they don't + # already exist. + + def gen_sub_directories + @outputdir.mkpath + end + + ## + # Copy over the stylesheet into the appropriate place in the output + # directory. + + def write_style_sheet + debug_msg "Copying static files" + options = { :verbose => $DEBUG_RDOC, :noop => @dry_run } + + BUILTIN_STYLE_ITEMS.each do |item| + install_rdoc_static_file @template_dir + item, "./#{item}", options + end + + @options.template_stylesheets.each do |stylesheet| + FileUtils.cp stylesheet, '.', options + end + + Dir[(@template_dir + "{js,images}/**/*").to_s].each do |path| + next if File.directory? path + next if File.basename(path) =~ /^\./ + + dst = Pathname.new(path).relative_path_from @template_dir + + install_rdoc_static_file @template_dir + path, dst, options + end + end + + ## + # Build the initial indices and output objects based on an array of TopLevel + # objects containing the extracted information. + + def generate + setup + + write_style_sheet + generate_index + generate_class_files + generate_file_files + generate_table_of_contents + @json_index.generate + @json_index.generate_gzipped + + copy_static + + rescue => e + debug_msg "%s: %s\n %s" % [ + e.class.name, e.message, e.backtrace.join("\n ") + ] + + raise + end + + ## + # Copies static files from the static_path into the output directory + + def copy_static + return if @options.static_path.empty? + + fu_options = { :verbose => $DEBUG_RDOC, :noop => @dry_run } + + @options.static_path.each do |path| + unless File.directory? path then + FileUtils.install path, @outputdir, fu_options.merge(:mode => 0644) + next + end + + Dir.chdir path do + Dir[File.join('**', '*')].each do |entry| + dest_file = @outputdir + entry + + if File.directory? entry then + FileUtils.mkdir_p entry, fu_options + else + FileUtils.install entry, dest_file, fu_options.merge(:mode => 0644) + end + end + end + end + end + + ## + # Return a list of the documented modules sorted by salience first, then + # by name. + + def get_sorted_module_list classes + classes.select do |klass| + klass.display? + end.sort + end + + ## + # Generate an index page which lists all the classes which are documented. + + def generate_index + setup + + template_file = @template_dir + 'index.rhtml' + return unless template_file.exist? + + debug_msg "Rendering the index page..." + + out_file = @base_dir + @options.op_dir + 'index.html' + rel_prefix = @outputdir.relative_path_from out_file.dirname + search_index_rel_prefix = rel_prefix + search_index_rel_prefix += @asset_rel_path if @file_output + + # suppress 1.9.3 warning + asset_rel_prefix = asset_rel_prefix = rel_prefix + @asset_rel_path + + @title = @options.title + + render_template template_file, out_file do |io| binding end + rescue => e + error = RDoc::Error.new \ + "error generating index.html: #{e.message} (#{e.class})" + error.set_backtrace e.backtrace + + raise error + end + + ## + # Generates a class file for +klass+ + + def generate_class klass, template_file = nil + setup + + current = klass + + template_file ||= @template_dir + 'class.rhtml' + + debug_msg " working on %s (%s)" % [klass.full_name, klass.path] + out_file = @outputdir + klass.path + rel_prefix = @outputdir.relative_path_from out_file.dirname + search_index_rel_prefix = rel_prefix + search_index_rel_prefix += @asset_rel_path if @file_output + + # suppress 1.9.3 warning + asset_rel_prefix = asset_rel_prefix = rel_prefix + @asset_rel_path + svninfo = svninfo = get_svninfo(current) + + @title = "#{klass.type} #{klass.full_name} - #{@options.title}" + + debug_msg " rendering #{out_file}" + render_template template_file, out_file do |io| binding end + end + + ## + # Generate a documentation file for each class and module + + def generate_class_files + setup + + template_file = @template_dir + 'class.rhtml' + template_file = @template_dir + 'classpage.rhtml' unless + template_file.exist? + return unless template_file.exist? + debug_msg "Generating class documentation in #{@outputdir}" + + current = nil + + @classes.each do |klass| + current = klass + + generate_class klass, template_file + end + rescue => e + error = RDoc::Error.new \ + "error generating #{current.path}: #{e.message} (#{e.class})" + error.set_backtrace e.backtrace + + raise error + end + + ## + # Generate a documentation file for each file + + def generate_file_files + setup + + page_file = @template_dir + 'page.rhtml' + fileinfo_file = @template_dir + 'fileinfo.rhtml' + + # for legacy templates + filepage_file = @template_dir + 'filepage.rhtml' unless + page_file.exist? or fileinfo_file.exist? + + return unless + page_file.exist? or fileinfo_file.exist? or filepage_file.exist? + + debug_msg "Generating file documentation in #{@outputdir}" + + out_file = nil + current = nil + + @files.each do |file| + current = file + + if file.text? and page_file.exist? then + generate_page file + next + end + + template_file = nil + out_file = @outputdir + file.path + debug_msg " working on %s (%s)" % [file.full_name, out_file] + rel_prefix = @outputdir.relative_path_from out_file.dirname + search_index_rel_prefix = rel_prefix + search_index_rel_prefix += @asset_rel_path if @file_output + + # suppress 1.9.3 warning + asset_rel_prefix = asset_rel_prefix = rel_prefix + @asset_rel_path + + unless filepage_file then + if file.text? then + next unless page_file.exist? + template_file = page_file + @title = file.page_name + else + next unless fileinfo_file.exist? + template_file = fileinfo_file + @title = "File: #{file.base_name}" + end + end + + @title += " - #{@options.title}" + template_file ||= filepage_file + + render_template template_file, out_file do |io| binding end + end + rescue => e + error = + RDoc::Error.new "error generating #{out_file}: #{e.message} (#{e.class})" + error.set_backtrace e.backtrace + + raise error + end + + ## + # Generate a page file for +file+ + + def generate_page file + setup + + template_file = @template_dir + 'page.rhtml' + + out_file = @outputdir + file.path + debug_msg " working on %s (%s)" % [file.full_name, out_file] + rel_prefix = @outputdir.relative_path_from out_file.dirname + search_index_rel_prefix = rel_prefix + search_index_rel_prefix += @asset_rel_path if @file_output + + # suppress 1.9.3 warning + current = current = file + asset_rel_prefix = asset_rel_prefix = rel_prefix + @asset_rel_path + + @title = "#{file.page_name} - #{@options.title}" + + debug_msg " rendering #{out_file}" + render_template template_file, out_file do |io| binding end + end + + ## + # Generates the 404 page for the RDoc servlet + + def generate_servlet_not_found message + setup + + template_file = @template_dir + 'servlet_not_found.rhtml' + return unless template_file.exist? + + debug_msg "Rendering the servlet 404 Not Found page..." + + rel_prefix = rel_prefix = '' + search_index_rel_prefix = rel_prefix + search_index_rel_prefix += @asset_rel_path if @file_output + + # suppress 1.9.3 warning + asset_rel_prefix = asset_rel_prefix = '' + + @title = 'Not Found' + + render_template template_file do |io| binding end + rescue => e + error = RDoc::Error.new \ + "error generating servlet_not_found: #{e.message} (#{e.class})" + error.set_backtrace e.backtrace + + raise error + end + + ## + # Generates the servlet root page for the RDoc servlet + + def generate_servlet_root installed + setup + + template_file = @template_dir + 'servlet_root.rhtml' + return unless template_file.exist? + + debug_msg 'Rendering the servlet root page...' + + rel_prefix = '.' + asset_rel_prefix = rel_prefix + search_index_rel_prefix = asset_rel_prefix + search_index_rel_prefix += @asset_rel_path if @file_output + + @title = 'Local RDoc Documentation' + + render_template template_file do |io| binding end + rescue => e + error = RDoc::Error.new \ + "error generating servlet_root: #{e.message} (#{e.class})" + error.set_backtrace e.backtrace + + raise error + end + + ## + # Generate an index page which lists all the classes which are documented. + + def generate_table_of_contents + setup + + template_file = @template_dir + 'table_of_contents.rhtml' + return unless template_file.exist? + + debug_msg "Rendering the Table of Contents..." + + out_file = @outputdir + 'table_of_contents.html' + rel_prefix = @outputdir.relative_path_from out_file.dirname + search_index_rel_prefix = rel_prefix + search_index_rel_prefix += @asset_rel_path if @file_output + + # suppress 1.9.3 warning + asset_rel_prefix = asset_rel_prefix = rel_prefix + @asset_rel_path + + @title = "Table of Contents - #{@options.title}" + + render_template template_file, out_file do |io| binding end + rescue => e + error = RDoc::Error.new \ + "error generating table_of_contents.html: #{e.message} (#{e.class})" + error.set_backtrace e.backtrace + + raise error + end + + def install_rdoc_static_file source, destination, options # :nodoc: + return unless source.exist? + + begin + FileUtils.mkdir_p File.dirname(destination), options + + begin + FileUtils.ln source, destination, options + rescue Errno::EEXIST + FileUtils.rm destination + retry + end + rescue + FileUtils.cp source, destination, options + end + end + + ## + # Prepares for generation of output from the current directory + + def setup + return if instance_variable_defined? :@outputdir + + @outputdir = Pathname.new(@options.op_dir).expand_path @base_dir + + return unless @store + + @classes = @store.all_classes_and_modules.sort + @files = @store.all_files.sort + @methods = @classes.map { |m| m.method_list }.flatten.sort + @modsort = get_sorted_module_list @classes + end + + ## + # Return a string describing the amount of time in the given number of + # seconds in terms a human can understand easily. + + def time_delta_string seconds + return 'less than a minute' if seconds < 60 + return "#{seconds / 60} minute#{seconds / 60 == 1 ? '' : 's'}" if + seconds < 3000 # 50 minutes + return 'about one hour' if seconds < 5400 # 90 minutes + return "#{seconds / 3600} hours" if seconds < 64800 # 18 hours + return 'one day' if seconds < 86400 # 1 day + return 'about one day' if seconds < 172800 # 2 days + return "#{seconds / 86400} days" if seconds < 604800 # 1 week + return 'about one week' if seconds < 1209600 # 2 week + return "#{seconds / 604800} weeks" if seconds < 7257600 # 3 months + return "#{seconds / 2419200} months" if seconds < 31536000 # 1 year + return "#{seconds / 31536000} years" + end + + # %q$Id: darkfish.rb 52 2009-01-07 02:08:11Z deveiant $" + SVNID_PATTERN = / + \$Id:\s + (\S+)\s # filename + (\d+)\s # rev + (\d{4}-\d{2}-\d{2})\s # Date (YYYY-MM-DD) + (\d{2}:\d{2}:\d{2}Z)\s # Time (HH:MM:SSZ) + (\w+)\s # committer + \$$ + /x + + ## + # Try to extract Subversion information out of the first constant whose + # value looks like a subversion Id tag. If no matching constant is found, + # and empty hash is returned. + + def get_svninfo klass + constants = klass.constants or return {} + + constants.find { |c| c.value =~ SVNID_PATTERN } or return {} + + filename, rev, date, time, committer = $~.captures + commitdate = Time.parse "#{date} #{time}" + + return { + :filename => filename, + :rev => Integer(rev), + :commitdate => commitdate, + :commitdelta => time_delta_string(Time.now - commitdate), + :committer => committer, + } + end + + ## + # Creates a template from its components and the +body_file+. + # + # For backwards compatibility, if +body_file+ contains "<html" the body is + # used directly. + + def assemble_template body_file + body = body_file.read + return body if body =~ /<html/ + + head_file = @template_dir + '_head.rhtml' + footer_file = @template_dir + '_footer.rhtml' + + <<-TEMPLATE +<!DOCTYPE html> + +<html> +<head> +#{head_file.read} + +#{body} + +#{footer_file.read} + TEMPLATE + end + + ## + # Renders the ERb contained in +file_name+ relative to the template + # directory and returns the result based on the current context. + + def render file_name + template_file = @template_dir + file_name + + template = template_for template_file, false, RDoc::ERBPartial + + template.filename = template_file.to_s + + template.result @context + end + + ## + # Load and render the erb template in the given +template_file+ and write + # it out to +out_file+. + # + # Both +template_file+ and +out_file+ should be Pathname-like objects. + # + # An io will be yielded which must be captured by binding in the caller. + + def render_template template_file, out_file = nil # :yield: io + io_output = out_file && !@dry_run && @file_output + erb_klass = io_output ? RDoc::ERBIO : ERB + + template = template_for template_file, true, erb_klass + + if io_output then + debug_msg "Outputting to %s" % [out_file.expand_path] + + out_file.dirname.mkpath + out_file.open 'w', 0644 do |io| + io.set_encoding @options.encoding if Object.const_defined? :Encoding + + @context = yield io + + template_result template, @context, template_file + end + else + @context = yield nil + + output = template_result template, @context, template_file + + debug_msg " would have written %d characters to %s" % [ + output.length, out_file.expand_path + ] if @dry_run + + output + end + end + + ## + # Creates the result for +template+ with +context+. If an error is raised a + # Pathname +template_file+ will indicate the file where the error occurred. + + def template_result template, context, template_file + template.filename = template_file.to_s + template.result context + rescue NoMethodError => e + raise RDoc::Error, "Error while evaluating %s: %s" % [ + template_file.expand_path, + e.message, + ], e.backtrace + end + + ## + # Retrieves a cache template for +file+, if present, or fills the cache. + + def template_for file, page = true, klass = ERB + template = @template_cache[file] + + return template if template + + if page then + template = assemble_template file + erbout = 'io' + else + template = file.read + template = template.encode @options.encoding if + Object.const_defined? :Encoding + + file_var = File.basename(file).sub(/\..*/, '') + + erbout = "_erbout_#{file_var}" + end + + template = klass.new template, nil, '<>', erbout + @template_cache[file] = template + template + end + +end + diff --git a/jni/ruby/lib/rdoc/generator/json_index.rb b/jni/ruby/lib/rdoc/generator/json_index.rb new file mode 100644 index 0000000..9d6f0d4 --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/json_index.rb @@ -0,0 +1,292 @@ +require 'json' +require 'zlib' + +## +# The JsonIndex generator is designed to complement an HTML generator and +# produces a JSON search index. This generator is derived from sdoc by +# Vladimir Kolesnikov and contains verbatim code written by him. +# +# This generator is designed to be used with a regular HTML generator: +# +# class RDoc::Generator::Darkfish +# def initialize options +# # ... +# @base_dir = Pathname.pwd.expand_path +# +# @json_index = RDoc::Generator::JsonIndex.new self, options +# end +# +# def generate +# # ... +# @json_index.generate +# end +# end +# +# == Index Format +# +# The index is output as a JSON file assigned to the global variable +# +search_data+. The structure is: +# +# var search_data = { +# "index": { +# "searchIndex": +# ["a", "b", ...], +# "longSearchIndex": +# ["a", "a::b", ...], +# "info": [ +# ["A", "A", "A.html", "", ""], +# ["B", "A::B", "A::B.html", "", ""], +# ... +# ] +# } +# } +# +# The same item is described across the +searchIndex+, +longSearchIndex+ and +# +info+ fields. The +searchIndex+ field contains the item's short name, the +# +longSearchIndex+ field contains the full_name (when appropriate) and the +# +info+ field contains the item's name, full_name, path, parameters and a +# snippet of the item's comment. +# +# == LICENSE +# +# Copyright (c) 2009 Vladimir Kolesnikov +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +class RDoc::Generator::JsonIndex + + include RDoc::Text + + ## + # Where the search index lives in the generated output + + SEARCH_INDEX_FILE = File.join 'js', 'search_index.js' + + attr_reader :index # :nodoc: + + ## + # Creates a new generator. +parent_generator+ is used to determine the + # class_dir and file_dir of links in the output index. + # + # +options+ are the same options passed to the parent generator. + + def initialize parent_generator, options + @parent_generator = parent_generator + @store = parent_generator.store + @options = options + + @template_dir = File.expand_path '../template/json_index', __FILE__ + @base_dir = @parent_generator.base_dir + + @classes = nil + @files = nil + @index = nil + end + + ## + # Builds the JSON index as a Hash. + + def build_index + reset @store.all_files.sort, @store.all_classes_and_modules.sort + + index_classes + index_methods + index_pages + + { :index => @index } + end + + ## + # Output progress information if debugging is enabled + + def debug_msg *msg + return unless $DEBUG_RDOC + $stderr.puts(*msg) + end + + ## + # Writes the JSON index to disk + + def generate + debug_msg "Generating JSON index" + + debug_msg " writing search index to %s" % SEARCH_INDEX_FILE + data = build_index + + return if @options.dry_run + + out_dir = @base_dir + @options.op_dir + index_file = out_dir + SEARCH_INDEX_FILE + + FileUtils.mkdir_p index_file.dirname, :verbose => $DEBUG_RDOC + + index_file.open 'w', 0644 do |io| + io.set_encoding Encoding::UTF_8 if Object.const_defined? :Encoding + io.write 'var search_data = ' + + JSON.dump data, io, 0 + end + + Dir.chdir @template_dir do + Dir['**/*.js'].each do |source| + dest = File.join out_dir, source + + FileUtils.install source, dest, :mode => 0644, :verbose => $DEBUG_RDOC + end + end + end + + ## + # Compress the search_index.js file using gzip + + def generate_gzipped + debug_msg "Compressing generated JSON index" + out_dir = @base_dir + @options.op_dir + + search_index_file = out_dir + SEARCH_INDEX_FILE + outfile = out_dir + "#{search_index_file}.gz" + + debug_msg "Reading the JSON index file from %s" % search_index_file + search_index = search_index_file.read + + debug_msg "Writing gzipped search index to %s" % outfile + + Zlib::GzipWriter.open(outfile) do |gz| + gz.mtime = File.mtime(search_index_file) + gz.orig_name = search_index_file.to_s + gz.write search_index + gz.close + end + + # GZip the rest of the js files + Dir.chdir @template_dir do + Dir['**/*.js'].each do |source| + dest = out_dir + source + outfile = out_dir + "#{dest}.gz" + + debug_msg "Reading the original js file from %s" % dest + data = dest.read + + debug_msg "Writing gzipped file to %s" % outfile + + Zlib::GzipWriter.open(outfile) do |gz| + gz.mtime = File.mtime(dest) + gz.orig_name = dest.to_s + gz.write data + gz.close + end + end + end + end + + ## + # Adds classes and modules to the index + + def index_classes + debug_msg " generating class search index" + + documented = @classes.uniq.select do |klass| + klass.document_self_or_methods + end + + documented.each do |klass| + debug_msg " #{klass.full_name}" + record = klass.search_record + @index[:searchIndex] << search_string(record.shift) + @index[:longSearchIndex] << search_string(record.shift) + @index[:info] << record + end + end + + ## + # Adds methods to the index + + def index_methods + debug_msg " generating method search index" + + list = @classes.uniq.map do |klass| + klass.method_list + end.flatten.sort_by do |method| + [method.name, method.parent.full_name] + end + + list.each do |method| + debug_msg " #{method.full_name}" + record = method.search_record + @index[:searchIndex] << "#{search_string record.shift}()" + @index[:longSearchIndex] << "#{search_string record.shift}()" + @index[:info] << record + end + end + + ## + # Adds pages to the index + + def index_pages + debug_msg " generating pages search index" + + pages = @files.select do |file| + file.text? + end + + pages.each do |page| + debug_msg " #{page.page_name}" + record = page.search_record + @index[:searchIndex] << search_string(record.shift) + @index[:longSearchIndex] << '' + record.shift + @index[:info] << record + end + end + + ## + # The directory classes are written to + + def class_dir + @parent_generator.class_dir + end + + ## + # The directory files are written to + + def file_dir + @parent_generator.file_dir + end + + def reset files, classes # :nodoc: + @files = files + @classes = classes + + @index = { + :searchIndex => [], + :longSearchIndex => [], + :info => [] + } + end + + ## + # Removes whitespace and downcases +string+ + + def search_string string + string.downcase.gsub(/\s/, '') + end + +end + diff --git a/jni/ruby/lib/rdoc/generator/markup.rb b/jni/ruby/lib/rdoc/generator/markup.rb new file mode 100644 index 0000000..788e5a4 --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/markup.rb @@ -0,0 +1,169 @@ +## +# Handle common RDoc::Markup tasks for various CodeObjects +# +# This module is loaded by generators. It allows RDoc's CodeObject tree to +# avoid loading generator code to improve startup time for +ri+. + +module RDoc::Generator::Markup + + ## + # Generates a relative URL from this object's path to +target_path+ + + def aref_to(target_path) + RDoc::Markup::ToHtml.gen_relative_url path, target_path + end + + ## + # Generates a relative URL from +from_path+ to this object's path + + def as_href(from_path) + RDoc::Markup::ToHtml.gen_relative_url from_path, path + end + + ## + # Handy wrapper for marking up this object's comment + + def description + markup @comment + end + + ## + # Creates an RDoc::Markup::ToHtmlCrossref formatter + + def formatter + return @formatter if defined? @formatter + + options = @store.rdoc.options + this = RDoc::Context === self ? self : @parent + + @formatter = RDoc::Markup::ToHtmlCrossref.new options, this.path, this + @formatter.code_object = self + @formatter + end + + ## + # Build a webcvs URL starting for the given +url+ with +full_path+ appended + # as the destination path. If +url+ contains '%s' +full_path+ will be + # will replace the %s using sprintf on the +url+. + + def cvs_url(url, full_path) + if /%s/ =~ url then + sprintf url, full_path + else + url + full_path + end + end + +end + +class RDoc::CodeObject + + include RDoc::Generator::Markup + +end + +class RDoc::MethodAttr + + @add_line_numbers = false + + class << self + ## + # Allows controlling whether <tt>#markup_code</tt> adds line numbers to + # the source code. + + attr_accessor :add_line_numbers + end + + ## + # Prepend +src+ with line numbers. Relies on the first line of a source + # code listing having: + # + # # File xxxxx, line dddd + # + # If it has this comment then line numbers are added to +src+ and the <tt>, + # line dddd</tt> portion of the comment is removed. + + def add_line_numbers(src) + return unless src.sub!(/\A(.*)(, line (\d+))/, '\1') + first = $3.to_i - 1 + last = first + src.count("\n") + size = last.to_s.length + + line = first + src.gsub!(/^/) do + res = if line == first then + " " * (size + 1) + else + "<span class=\"line-num\">%2$*1$d</span> " % [size, line] + end + + line += 1 + res + end + end + + ## + # Turns the method's token stream into HTML. + # + # Prepends line numbers if +add_line_numbers+ is true. + + def markup_code + return '' unless @token_stream + + src = RDoc::TokenStream.to_html @token_stream + + # dedent the source + indent = src.length + lines = src.lines.to_a + lines.shift if src =~ /\A.*#\ *File/i # remove '# File' comment + lines.each do |line| + if line =~ /^ *(?=\S)/ + n = $&.length + indent = n if n < indent + break if n == 0 + end + end + src.gsub!(/^#{' ' * indent}/, '') if indent > 0 + + add_line_numbers(src) if RDoc::MethodAttr.add_line_numbers + + src + end + +end + +class RDoc::ClassModule + + ## + # Handy wrapper for marking up this class or module's comment + + def description + markup @comment_location + end + +end + +class RDoc::Context::Section + + include RDoc::Generator::Markup + +end + +class RDoc::TopLevel + + ## + # Returns a URL for this source file on some web repository. Use the -W + # command line option to set. + + def cvs_url + url = @store.rdoc.options.webcvs + + if /%s/ =~ url then + url % @relative_name + else + url + @relative_name + end + end + +end + diff --git a/jni/ruby/lib/rdoc/generator/pot.rb b/jni/ruby/lib/rdoc/generator/pot.rb new file mode 100644 index 0000000..db6f3a0 --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/pot.rb @@ -0,0 +1,97 @@ +## +# Generates a POT file. +# +# Here is a translator work flow with the generator. +# +# == Create .pot +# +# You create .pot file by pot formatter: +# +# % rdoc --format pot +# +# It generates doc/rdoc.pot. +# +# == Create .po +# +# You create .po file from doc/rdoc.pot. This operation is needed only +# the first time. This work flow assumes that you are a translator +# for Japanese. +# +# You create locale/ja/rdoc.po from doc/rdoc.pot. You can use msginit +# provided by GNU gettext or rmsginit provided by gettext gem. This +# work flow uses gettext gem because it is more portable than GNU +# gettext for Rubyists. Gettext gem is implemented by pure Ruby. +# +# % gem install gettext +# % mkdir -p locale/ja +# % rmsginit --input doc/rdoc.pot --output locale/ja/rdoc.po --locale ja +# +# Translate messages in .po +# +# You translate messages in .po by a PO file editor. po-mode.el exists +# for Emacs users. There are some GUI tools such as GTranslator. +# There are some Web services such as POEditor and Tansifex. You can +# edit by your favorite text editor because .po is a text file. +# Generate localized documentation +# +# You can generate localized documentation with locale/ja/rdoc.po: +# +# % rdoc --locale ja +# +# You can find documentation in Japanese in doc/. Yay! +# +# == Update translation +# +# You need to update translation when your application is added or +# modified messages. +# +# You can update .po by the following command lines: +# +# % rdoc --format pot +# % rmsgmerge --update locale/ja/rdoc.po doc/rdoc.pot +# +# You edit locale/ja/rdoc.po to translate new messages. + +class RDoc::Generator::POT + + RDoc::RDoc.add_generator self + + ## + # Description of this generator + + DESCRIPTION = 'creates .pot file' + + ## + # Set up a new .pot generator + + def initialize store, options #:not-new: + @options = options + @store = store + end + + ## + # Writes .pot to disk. + + def generate + po = extract_messages + pot_path = 'rdoc.pot' + File.open(pot_path, "w") do |pot| + pot.print(po.to_s) + end + end + + def class_dir + nil + end + + private + def extract_messages + extractor = MessageExtractor.new(@store) + extractor.extract + end + + autoload :MessageExtractor, 'rdoc/generator/pot/message_extractor' + autoload :PO, 'rdoc/generator/pot/po' + autoload :POEntry, 'rdoc/generator/pot/po_entry' + +end diff --git a/jni/ruby/lib/rdoc/generator/pot/message_extractor.rb b/jni/ruby/lib/rdoc/generator/pot/message_extractor.rb new file mode 100644 index 0000000..ceabc52 --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/pot/message_extractor.rb @@ -0,0 +1,67 @@ +## +# Extracts message from RDoc::Store + +class RDoc::Generator::POT::MessageExtractor + + ## + # Creates a message extractor for +store+. + + def initialize store + @store = store + @po = RDoc::Generator::POT::PO.new + end + + ## + # Extracts messages from +store+, stores them into + # RDoc::Generator::POT::PO and returns it. + + def extract + @store.all_classes_and_modules.each do |klass| + extract_from_klass(klass) + end + @po + end + + private + + def extract_from_klass klass + extract_text(klass.comment_location, klass.full_name) + + klass.each_section do |section, constants, attributes| + extract_text(section.title ,"#{klass.full_name}: section title") + section.comments.each do |comment| + extract_text(comment, "#{klass.full_name}: #{section.title}") + end + end + + klass.each_constant do |constant| + extract_text(constant.comment, constant.full_name) + end + + klass.each_attribute do |attribute| + extract_text(attribute.comment, attribute.full_name) + end + + klass.each_method do |method| + extract_text(method.comment, method.full_name) + end + end + + def extract_text text, comment, location = nil + return if text.nil? + + options = { + :extracted_comment => comment, + :references => [location].compact, + } + i18n_text = RDoc::I18n::Text.new(text) + i18n_text.extract_messages do |part| + @po.add(entry(part[:paragraph], options)) + end + end + + def entry msgid, options + RDoc::Generator::POT::POEntry.new(msgid, options) + end + +end diff --git a/jni/ruby/lib/rdoc/generator/pot/po.rb b/jni/ruby/lib/rdoc/generator/pot/po.rb new file mode 100644 index 0000000..6a6b582 --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/pot/po.rb @@ -0,0 +1,83 @@ +## +# Generates a PO format text + +class RDoc::Generator::POT::PO + + ## + # Creates an object that represents PO format. + + def initialize + @entries = {} + add_header + end + + ## + # Adds a PO entry to the PO. + + def add entry + existing_entry = @entries[entry.msgid] + if existing_entry + entry = existing_entry.merge(entry) + end + @entries[entry.msgid] = entry + end + + ## + # Returns PO format text for the PO. + + def to_s + po = '' + sort_entries.each do |entry| + po << "\n" unless po.empty? + po << entry.to_s + end + po + end + + private + + def add_header + add(header_entry) + end + + def header_entry + comment = <<-COMMENT +SOME DESCRIPTIVE TITLE. +Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +This file is distributed under the same license as the PACKAGE package. +FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. + COMMENT + + content = <<-CONTENT +Project-Id-Version: PACKAGE VERSEION +Report-Msgid-Bugs-To: +PO-Revision-Date: YEAR-MO_DA HO:MI+ZONE +Last-Translator: FULL NAME <EMAIL@ADDRESS> +Language-Team: LANGUAGE <LL@li.org> +Language: +MIME-Version: 1.0 +Content-Type: text/plain; charset=CHARSET +Content-Transfer-Encoding: 8bit +Plural-Forms: nplurals=INTEGER; plural=EXPRESSION; + CONTENT + + options = { + :msgstr => content, + :translator_comment => comment, + :flags => ['fuzzy'], + } + RDoc::Generator::POT::POEntry.new('', options) + end + + def sort_entries + headers, messages = @entries.values.partition do |entry| + entry.msgid.empty? + end + # TODO: sort by location + sorted_messages = messages.sort_by do |entry| + entry.msgid + end + headers + sorted_messages + end + +end diff --git a/jni/ruby/lib/rdoc/generator/pot/po_entry.rb b/jni/ruby/lib/rdoc/generator/pot/po_entry.rb new file mode 100644 index 0000000..d4cef59 --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/pot/po_entry.rb @@ -0,0 +1,140 @@ +## +# A PO entry in PO + +class RDoc::Generator::POT::POEntry + + # The msgid content + attr_reader :msgid + + # The msgstr content + attr_reader :msgstr + + # The comment content created by translator (PO editor) + attr_reader :translator_comment + + # The comment content extracted from source file + attr_reader :extracted_comment + + # The locations where the PO entry is extracted + attr_reader :references + + # The flags of the PO entry + attr_reader :flags + + ## + # Creates a PO entry for +msgid+. Other valus can be specified by + # +options+. + + def initialize msgid, options = {} + @msgid = msgid + @msgstr = options[:msgstr] || "" + @translator_comment = options[:translator_comment] + @extracted_comment = options[:extracted_comment] + @references = options[:references] || [] + @flags = options[:flags] || [] + end + + ## + # Returns the PO entry in PO format. + + def to_s + entry = '' + entry << format_translator_comment + entry << format_extracted_comment + entry << format_references + entry << format_flags + entry << <<-ENTRY +msgid #{format_message(@msgid)} +msgstr #{format_message(@msgstr)} + ENTRY + end + + ## + # Merges the PO entry with +other_entry+. + + def merge other_entry + options = { + :extracted_comment => merge_string(@extracted_comment, + other_entry.extracted_comment), + :translator_comment => merge_string(@translator_comment, + other_entry.translator_comment), + :references => merge_array(@references, + other_entry.references), + :flags => merge_array(@flags, + other_entry.flags), + } + self.class.new(@msgid, options) + end + + private + + def format_comment mark, comment + return '' unless comment + return '' if comment.empty? + + formatted_comment = '' + comment.each_line do |line| + formatted_comment << "#{mark} #{line}" + end + formatted_comment << "\n" unless formatted_comment.end_with?("\n") + formatted_comment + end + + def format_translator_comment + format_comment('#', @translator_comment) + end + + def format_extracted_comment + format_comment('#.', @extracted_comment) + end + + def format_references + return '' if @references.empty? + + formatted_references = '' + @references.sort.each do |file, line| + formatted_references << "\#: #{file}:#{line}\n" + end + formatted_references + end + + def format_flags + return '' if @flags.empty? + + formatted_flags = flags.join(",") + "\#, #{formatted_flags}\n" + end + + def format_message message + return "\"#{escape(message)}\"" unless message.include?("\n") + + formatted_message = '""' + message.each_line do |line| + formatted_message << "\n" + formatted_message << "\"#{escape(line)}\"" + end + formatted_message + end + + def escape string + string.gsub(/["\\\t\n]/) do |special_character| + case special_character + when "\t" + "\\t" + when "\n" + "\\n" + else + "\\#{special_character}" + end + end + end + + def merge_string string1, string2 + [string1, string2].compact.join("\n") + end + + def merge_array array1, array2 + (array1 + array2).uniq + end + +end diff --git a/jni/ruby/lib/rdoc/generator/ri.rb b/jni/ruby/lib/rdoc/generator/ri.rb new file mode 100644 index 0000000..b9c4141 --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/ri.rb @@ -0,0 +1,30 @@ +## +# Generates ri data files + +class RDoc::Generator::RI + + RDoc::RDoc.add_generator self + + ## + # Description of this generator + + DESCRIPTION = 'creates ri data files' + + ## + # Set up a new ri generator + + def initialize store, options #:not-new: + @options = options + @store = store + @store.path = '.' + end + + ## + # Writes the parsed data store to disk for use by ri. + + def generate + @store.save + end + +end + diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/.document b/jni/ruby/lib/rdoc/generator/template/darkfish/.document new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/.document diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/_footer.rhtml b/jni/ruby/lib/rdoc/generator/template/darkfish/_footer.rhtml new file mode 100644 index 0000000..fe5822c --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/_footer.rhtml @@ -0,0 +1,5 @@ +<footer id="validator-badges" role="contentinfo"> + <p><a href="http://validator.w3.org/check/referer">Validate</a> + <p>Generated by <a href="http://docs.seattlerb.org/rdoc/">RDoc</a> <%= RDoc::VERSION %>. + <p>Based on <a href="http://deveiate.org/projects/Darkfish-RDoc/">Darkfish</a> by <a href="http://deveiate.org">Michael Granger</a>. +</footer> diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/_head.rhtml b/jni/ruby/lib/rdoc/generator/template/darkfish/_head.rhtml new file mode 100644 index 0000000..70f1c18 --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/_head.rhtml @@ -0,0 +1,19 @@ +<meta charset="<%= @options.charset %>"> + +<title><%= h @title %></title> + +<script type="text/javascript"> + var rdoc_rel_prefix = "<%= rel_prefix %>/"; +</script> + +<script src="<%= asset_rel_prefix %>/js/jquery.js"></script> +<script src="<%= asset_rel_prefix %>/js/darkfish.js"></script> + +<link href="<%= asset_rel_prefix %>/css/fonts.css" rel="stylesheet"> +<link href="<%= asset_rel_prefix %>/css/rdoc.css" rel="stylesheet"> +<% if @options.template_stylesheets.flatten.any? then %> +<% @options.template_stylesheets.flatten.each do |stylesheet| %> +<link href="<%= asset_rel_prefix %>/<%= File.basename stylesheet %>" rel="stylesheet"> +<% end %> +<% end %> + diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/_sidebar_VCS_info.rhtml b/jni/ruby/lib/rdoc/generator/template/darkfish/_sidebar_VCS_info.rhtml new file mode 100644 index 0000000..e889f80 --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/_sidebar_VCS_info.rhtml @@ -0,0 +1,19 @@ +<% if !svninfo.empty? then %> +<div id="file-svninfo-section" class="nav-section"> + <h3>VCS Info</h3> + + <div class="section-body"> + <dl class="svninfo"> + <dt>Rev + <dd><%= svninfo[:rev] %> + + <dt>Last Checked In + <dd><%= svninfo[:commitdate].strftime('%Y-%m-%d %H:%M:%S') %> + (<%= svninfo[:commitdelta] %> ago) + + <dt>Checked in by + <dd><%= svninfo[:committer] %> + </dl> + </div> +</div> +<% end %> diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/_sidebar_classes.rhtml b/jni/ruby/lib/rdoc/generator/template/darkfish/_sidebar_classes.rhtml new file mode 100644 index 0000000..fe54d83 --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/_sidebar_classes.rhtml @@ -0,0 +1,9 @@ +<div id="classindex-section" class="nav-section"> + <h3>Class and Module Index</h3> + + <ul class="link-list"> + <% @modsort.each do |index_klass| %> + <li><a href="<%= rel_prefix %>/<%= index_klass.path %>"><%= index_klass.full_name %></a> + <% end %> + </ul> +</div> diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/_sidebar_extends.rhtml b/jni/ruby/lib/rdoc/generator/template/darkfish/_sidebar_extends.rhtml new file mode 100644 index 0000000..2bd8efe --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/_sidebar_extends.rhtml @@ -0,0 +1,15 @@ +<% unless klass.extends.empty? then %> +<div id="extends-section" class="nav-section"> + <h3>Extended With Modules</h3> + + <ul class="link-list"> + <% klass.each_extend do |ext| %> + <% unless String === ext.module then %> + <li><a class="extend" href="<%= klass.aref_to ext.module.path %>"><%= ext.module.full_name %></a> + <% else %> + <li><span class="extend"><%= ext.name %></span> + <% end %> + <% end %> + </ul> +</div> +<% end %> diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/_sidebar_in_files.rhtml b/jni/ruby/lib/rdoc/generator/template/darkfish/_sidebar_in_files.rhtml new file mode 100644 index 0000000..0ba1d2b --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/_sidebar_in_files.rhtml @@ -0,0 +1,9 @@ +<div id="file-list-section" class="nav-section"> + <h3>Defined In</h3> + + <ul> +<% klass.in_files.each do |tl| %> + <li><%= h tl.relative_name %> +<% end %> + </ul> +</div> diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/_sidebar_includes.rhtml b/jni/ruby/lib/rdoc/generator/template/darkfish/_sidebar_includes.rhtml new file mode 100644 index 0000000..d141098 --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/_sidebar_includes.rhtml @@ -0,0 +1,15 @@ +<% unless klass.includes.empty? then %> +<div id="includes-section" class="nav-section"> + <h3>Included Modules</h3> + + <ul class="link-list"> + <% klass.each_include do |inc| %> + <% unless String === inc.module then %> + <li><a class="include" href="<%= klass.aref_to inc.module.path %>"><%= inc.module.full_name %></a> + <% else %> + <li><span class="include"><%= inc.name %></span> + <% end %> + <% end %> + </ul> +</div> +<% end %> diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/_sidebar_installed.rhtml b/jni/ruby/lib/rdoc/generator/template/darkfish/_sidebar_installed.rhtml new file mode 100644 index 0000000..1285bfd --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/_sidebar_installed.rhtml @@ -0,0 +1,15 @@ +<div id="home-section" class="nav-section"> + <h3>Documentation</h3> + + <ul> + <% installed.each do |name, href, exists, type, _| %> + <% next if type == :extra %> + <li class="folder"> + <% if exists then %> + <a href="<%= href %>"><%= h name %></a> + <% else %> + <%= h name %> + <% end %> + <% end %> + </ul> +</div> diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/_sidebar_methods.rhtml b/jni/ruby/lib/rdoc/generator/template/darkfish/_sidebar_methods.rhtml new file mode 100644 index 0000000..45df08d --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/_sidebar_methods.rhtml @@ -0,0 +1,12 @@ +<% unless klass.method_list.empty? then %> +<!-- Method Quickref --> +<div id="method-list-section" class="nav-section"> + <h3>Methods</h3> + + <ul class="link-list" role="directory"> + <% klass.each_method do |meth| %> + <li <% if meth.calls_super %>class="calls-super" <% end %>><a href="#<%= meth.aref %>"><%= meth.singleton ? '::' : '#' %><%= h meth.name %></a> + <% end %> + </ul> +</div> +<% end %> diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/_sidebar_navigation.rhtml b/jni/ruby/lib/rdoc/generator/template/darkfish/_sidebar_navigation.rhtml new file mode 100644 index 0000000..d7f3308 --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/_sidebar_navigation.rhtml @@ -0,0 +1,11 @@ +<div id="home-section" role="region" title="Quick navigation" class="nav-section"> + <h2> + <a href="<%= rel_prefix %>/index.html" rel="home">Home</a> + </h2> + + <div id="table-of-contents-navigation"> + <a href="<%= rel_prefix %>/table_of_contents.html#pages">Pages</a> + <a href="<%= rel_prefix %>/table_of_contents.html#classes">Classes</a> + <a href="<%= rel_prefix %>/table_of_contents.html#methods">Methods</a> + </div> +</div> diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/_sidebar_pages.rhtml b/jni/ruby/lib/rdoc/generator/template/darkfish/_sidebar_pages.rhtml new file mode 100644 index 0000000..5f39825 --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/_sidebar_pages.rhtml @@ -0,0 +1,12 @@ +<% simple_files = @files.select { |f| f.text? } %> +<% unless simple_files.empty? then %> +<div id="fileindex-section" class="nav-section"> + <h3>Pages</h3> + + <ul class="link-list"> + <% simple_files.each do |f| %> + <li><a href="<%= rel_prefix %>/<%= f.path %>"><%= h f.page_name %></a> + <% end %> + </ul> +</div> +<% end %> diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/_sidebar_parent.rhtml b/jni/ruby/lib/rdoc/generator/template/darkfish/_sidebar_parent.rhtml new file mode 100644 index 0000000..cc04852 --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/_sidebar_parent.rhtml @@ -0,0 +1,11 @@ +<% if klass.type == 'class' then %> +<div id="parent-class-section" class="nav-section"> + <h3>Parent</h3> + + <% if klass.superclass and not String === klass.superclass then %> + <p class="link"><a href="<%= klass.aref_to klass.superclass.path %>"><%= klass.superclass.full_name %></a> + <% else %> + <p class="link"><%= klass.superclass %> + <% end %> +</div> +<% end %> diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/_sidebar_search.rhtml b/jni/ruby/lib/rdoc/generator/template/darkfish/_sidebar_search.rhtml new file mode 100644 index 0000000..9c49b31 --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/_sidebar_search.rhtml @@ -0,0 +1,14 @@ +<div id="search-section" role="search" class="project-section initially-hidden"> + <form action="#" method="get" accept-charset="utf-8"> + <div id="search-field-wrapper"> + <input id="search-field" role="combobox" aria-label="Search" + aria-autocomplete="list" aria-controls="search-results" + type="text" name="search" placeholder="Search" spellcheck="false" + title="Type to search, Up and Down to navigate, Enter to load"> + </div> + + <ul id="search-results" aria-label="Search Results" + aria-busy="false" aria-expanded="false" + aria-atomic="false" class="initially-hidden"></ul> + </form> +</div> diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/_sidebar_sections.rhtml b/jni/ruby/lib/rdoc/generator/template/darkfish/_sidebar_sections.rhtml new file mode 100644 index 0000000..15ff78b --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/_sidebar_sections.rhtml @@ -0,0 +1,11 @@ +<% unless klass.sections.length == 1 then %> +<div id="sections-section" class="nav-section"> + <h3>Sections</h3> + + <ul class="link-list" role="directory"> + <% klass.sort_sections.each do |section| %> + <li><a href="#<%= section.aref %>"><%= h section.title %></a></li> + <% end %> + </ul> +</div> +<% end %> diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/_sidebar_table_of_contents.rhtml b/jni/ruby/lib/rdoc/generator/template/darkfish/_sidebar_table_of_contents.rhtml new file mode 100644 index 0000000..b58e6b3 --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/_sidebar_table_of_contents.rhtml @@ -0,0 +1,18 @@ +<% comment = if current.respond_to? :comment_location then + current.comment_location + else + current.comment + end + table = current.parse(comment).table_of_contents + + if table.length > 1 then %> +<div class="nav-section"> + <h3>Table of Contents</h3> + + <ul class="link-list" role="directory"> +<% table.each do |heading| %> + <li><a href="#<%= heading.label current %>"><%= heading.plain_html %></a> +<% end %> + </ul> +</div> +<% end %> diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/class.rhtml b/jni/ruby/lib/rdoc/generator/template/darkfish/class.rhtml new file mode 100644 index 0000000..b497000 --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/class.rhtml @@ -0,0 +1,174 @@ +<body id="top" role="document" class="<%= klass.type %>"> +<nav role="navigation"> + <div id="project-navigation"> + <%= render '_sidebar_navigation.rhtml' %> + <%= render '_sidebar_search.rhtml' %> + </div> + + <%= render '_sidebar_table_of_contents.rhtml' %> + + <div id="class-metadata"> + <%= render '_sidebar_sections.rhtml' %> + <%= render '_sidebar_parent.rhtml' %> + <%= render '_sidebar_includes.rhtml' %> + <%= render '_sidebar_extends.rhtml' %> + <%= render '_sidebar_methods.rhtml' %> + </div> +</nav> + +<main role="main" aria-labelledby="<%=h klass.aref %>"> + <h1 id="<%=h klass.aref %>" class="<%= klass.type %>"> + <%= klass.type %> <%= klass.full_name %> + </h1> + + <section class="description"> + <%= klass.description %> + </section> + + <% klass.each_section do |section, constants, attributes| %> + <% constants = constants.select { |const| const.display? } %> + <% attributes = attributes.select { |attr| attr.display? } %> + <section id="<%= section.aref %>" class="documentation-section"> + <% if section.title then %> + <header class="documentation-section-title"> + <h2> + <%= section.title %> + </h2> + <span class="section-click-top"> + <a href="#top">↑ top</a> + </span> + </header> + <% end %> + + <% if section.comment then %> + <div> + <%= section.description %> + </div> + <% end %> + + <% unless constants.empty? then %> + <section class="constants-list"> + <header> + <h3>Constants</h3> + </header> + <dl> + <% constants.each do |const| %> + <dt id="<%= const.name %>"><%= const.name %> + <% if const.comment then %> + <dd><%= const.description.strip %> + <% else %> + <dd class="missing-docs">(Not documented) + <% end %> + <% end %> + </dl> + </section> + <% end %> + + <% unless attributes.empty? then %> + <section class="attribute-method-details" class="method-section"> + <header> + <h3>Attributes</h3> + </header> + + <% attributes.each do |attrib| %> + <div id="<%= attrib.aref %>" class="method-detail"> + <div class="method-heading attribute-method-heading"> + <span class="method-name"><%= h attrib.name %></span><span + class="attribute-access-type">[<%= attrib.rw %>]</span> + </div> + + <div class="method-description"> + <% if attrib.comment then %> + <%= attrib.description.strip %> + <% else %> + <p class="missing-docs">(Not documented) + <% end %> + </div> + </div> + <% end %> + </section> + <% end %> + + <% klass.methods_by_type(section).each do |type, visibilities| + next if visibilities.empty? + visibilities.each do |visibility, methods| + next if methods.empty? %> + <section id="<%= visibility %>-<%= type %>-<%= section.aref %>-method-details" class="method-section"> + <header> + <h3><%= visibility.to_s.capitalize %> <%= type.capitalize %> Methods</h3> + </header> + + <% methods.each do |method| %> + <div id="<%= method.aref %>" class="method-detail <%= method.is_alias_for ? "method-alias" : '' %>"> + <% if method.call_seq then %> + <% method.call_seq.strip.split("\n").each_with_index do |call_seq, i| %> + <div class="method-heading"> + <span class="method-callseq"> + <%= h(call_seq.strip. + gsub( /^\w+\./m, '')). + gsub(/(.*)[-=]>/, '\1→') %> + </span> + <% if i == 0 and method.token_stream then %> + <span class="method-click-advice">click to toggle source</span> + <% end %> + </div> + <% end %> + <% else %> + <div class="method-heading"> + <span class="method-name"><%= h method.name %></span><span + class="method-args"><%= method.param_seq %></span> + <% if method.token_stream then %> + <span class="method-click-advice">click to toggle source</span> + <% end %> + </div> + <% end %> + + <div class="method-description"> + <% if method.comment then %> + <%= method.description.strip %> + <% else %> + <p class="missing-docs">(Not documented) + <% end %> + <% if method.calls_super then %> + <div class="method-calls-super"> + Calls superclass method + <%= + method.superclass_method ? + method.formatter.link(method.superclass_method.full_name, method.superclass_method.full_name) : nil + %> + </div> + <% end %> + + <% if method.token_stream then %> + <div class="method-source-code" id="<%= method.html_name %>-source"> + <pre><%= method.markup_code %></pre> + </div> + <% end %> + </div> + + <% unless method.aliases.empty? then %> + <div class="aliases"> + Also aliased as: <%= method.aliases.map do |aka| + if aka.parent then # HACK lib/rexml/encodings + %{<a href="#{klass.aref_to aka.path}">#{h aka.name}</a>} + else + h aka.name + end + end.join ", " %> + </div> + <% end %> + + <% if method.is_alias_for then %> + <div class="aliases"> + Alias for: <a href="<%= klass.aref_to method.is_alias_for.path %>"><%= h method.is_alias_for.name %></a> + </div> + <% end %> + </div> + + <% end %> + </section> + <% end + end %> + </section> +<% end %> +</main> diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/css/fonts.css b/jni/ruby/lib/rdoc/generator/template/darkfish/css/fonts.css new file mode 100644 index 0000000..e9e7211 --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/css/fonts.css @@ -0,0 +1,167 @@ +/* + * Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), + * with Reserved Font Name "Source". All Rights Reserved. Source is a + * trademark of Adobe Systems Incorporated in the United States and/or other + * countries. + * + * This Font Software is licensed under the SIL Open Font License, Version + * 1.1. + * + * This license is copied below, and is also available with a FAQ at: + * http://scripts.sil.org/OFL + */ + +@font-face { + font-family: "Source Code Pro"; + font-style: normal; + font-weight: 400; + src: local("Source Code Pro"), + local("SourceCodePro-Regular"), + url("fonts/SourceCodePro-Regular.ttf") format("truetype"); +} + +@font-face { + font-family: "Source Code Pro"; + font-style: normal; + font-weight: 700; + src: local("Source Code Pro Bold"), + local("SourceCodePro-Bold"), + url("fonts/SourceCodePro-Bold.ttf") format("truetype"); +} + +/* + * Copyright (c) 2010, Łukasz Dziedzic (dziedzic@typoland.com), + * with Reserved Font Name Lato. + * + * This Font Software is licensed under the SIL Open Font License, Version + * 1.1. + * + * This license is copied below, and is also available with a FAQ at: + * http://scripts.sil.org/OFL + */ + +@font-face { + font-family: "Lato"; + font-style: normal; + font-weight: 300; + src: local("Lato Light"), + local("Lato-Light"), + url("fonts/Lato-Light.ttf") format("truetype"); +} + +@font-face { + font-family: "Lato"; + font-style: italic; + font-weight: 300; + src: local("Lato Light Italic"), + local("Lato-LightItalic"), + url("fonts/Lato-LightItalic.ttf") format("truetype"); +} + +@font-face { + font-family: "Lato"; + font-style: normal; + font-weight: 700; + src: local("Lato Regular"), + local("Lato-Regular"), + url("fonts/Lato-Regular.ttf") format("truetype"); +} + +@font-face { + font-family: "Lato"; + font-style: italic; + font-weight: 700; + src: local("Lato Italic"), + local("Lato-Italic"), + url("fonts/Lato-RegularItalic.ttf") format("truetype"); +} + +/* + * ----------------------------------------------------------- + * SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 + * ----------------------------------------------------------- + * + * PREAMBLE + * The goals of the Open Font License (OFL) are to stimulate worldwide + * development of collaborative font projects, to support the font creation + * efforts of academic and linguistic communities, and to provide a free and + * open framework in which fonts may be shared and improved in partnership + * with others. + * + * The OFL allows the licensed fonts to be used, studied, modified and + * redistributed freely as long as they are not sold by themselves. The + * fonts, including any derivative works, can be bundled, embedded, + * redistributed and/or sold with any software provided that any reserved + * names are not used by derivative works. The fonts and derivatives, + * however, cannot be released under any other type of license. The + * requirement for fonts to remain under this license does not apply + * to any document created using the fonts or their derivatives. + * + * DEFINITIONS + * "Font Software" refers to the set of files released by the Copyright + * Holder(s) under this license and clearly marked as such. This may + * include source files, build scripts and documentation. + * + * "Reserved Font Name" refers to any names specified as such after the + * copyright statement(s). + * + * "Original Version" refers to the collection of Font Software components as + * distributed by the Copyright Holder(s). + * + * "Modified Version" refers to any derivative made by adding to, deleting, + * or substituting -- in part or in whole -- any of the components of the + * Original Version, by changing formats or by porting the Font Software to a + * new environment. + * + * "Author" refers to any designer, engineer, programmer, technical + * writer or other person who contributed to the Font Software. + * + * PERMISSION & CONDITIONS + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of the Font Software, to use, study, copy, merge, embed, modify, + * redistribute, and sell modified and unmodified copies of the Font + * Software, subject to the following conditions: + * + * 1) Neither the Font Software nor any of its individual components, + * in Original or Modified Versions, may be sold by itself. + * + * 2) Original or Modified Versions of the Font Software may be bundled, + * redistributed and/or sold with any software, provided that each copy + * contains the above copyright notice and this license. These can be + * included either as stand-alone text files, human-readable headers or + * in the appropriate machine-readable metadata fields within text or + * binary files as long as those fields can be easily viewed by the user. + * + * 3) No Modified Version of the Font Software may use the Reserved Font + * Name(s) unless explicit written permission is granted by the corresponding + * Copyright Holder. This restriction only applies to the primary font name as + * presented to the users. + * + * 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font + * Software shall not be used to promote, endorse or advertise any + * Modified Version, except to acknowledge the contribution(s) of the + * Copyright Holder(s) and the Author(s) or with their explicit written + * permission. + * + * 5) The Font Software, modified or unmodified, in part or in whole, + * must be distributed entirely under this license, and must not be + * distributed under any other license. The requirement for fonts to + * remain under this license does not apply to any document created + * using the Font Software. + * + * TERMINATION + * This license becomes null and void if any of the above conditions are + * not met. + * + * DISCLAIMER + * THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT + * OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL + * DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM + * OTHER DEALINGS IN THE FONT SOFTWARE. + */ + diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/css/rdoc.css b/jni/ruby/lib/rdoc/generator/template/darkfish/css/rdoc.css new file mode 100644 index 0000000..2f4dca7 --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/css/rdoc.css @@ -0,0 +1,590 @@ +/* + * "Darkfish" Rdoc CSS + * $Id: rdoc.css 54 2009-01-27 01:09:48Z deveiant $ + * + * Author: Michael Granger <ged@FaerieMUD.org> + * + */ + +/* vim: ft=css et sw=2 ts=2 sts=2 */ +/* Base Green is: #6C8C22 */ + +* { padding: 0; margin: 0; } + +body { + background: #fafafa; + font-family: Lato, sans-serif; + font-weight: 300; +} + +h1 span, +h2 span, +h3 span, +h4 span, +h5 span, +h6 span { + position: relative; + + display: none; + padding-left: 1em; + line-height: 0; + vertical-align: baseline; + font-size: 10px; +} + +h1 span { top: -1.3em; } +h2 span { top: -1.2em; } +h3 span { top: -1.0em; } +h4 span { top: -0.8em; } +h5 span { top: -0.5em; } +h6 span { top: -0.5em; } + +h1:hover span, +h2:hover span, +h3:hover span, +h4:hover span, +h5:hover span, +h6:hover span { + display: inline; +} + +:link, +:visited { + color: #6C8C22; + text-decoration: none; +} + +:link:hover, +:visited:hover { + border-bottom: 1px dotted #6C8C22; +} + +code, +pre { + font-family: "Source Code Pro", Monaco, monospace; +} + +/* @group Generic Classes */ + +.initially-hidden { + display: none; +} + +#search-field { + width: 98%; + background: white; + border: none; + height: 1.5em; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + text-align: left; +} +#search-field:focus { + background: #f1edba; +} +#search-field:-moz-placeholder, +#search-field::-webkit-input-placeholder { + font-weight: bold; + color: #666; +} + +.missing-docs { + font-size: 120%; + background: white url(images/wrench_orange.png) no-repeat 4px center; + color: #ccc; + line-height: 2em; + border: 1px solid #d00; + opacity: 1; + padding-left: 20px; + text-indent: 24px; + letter-spacing: 3px; + font-weight: bold; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; +} + +.target-section { + border: 2px solid #dcce90; + border-left-width: 8px; + padding: 0 1em; + background: #fff3c2; +} + +/* @end */ + +/* @group Index Page, Standalone file pages */ +.table-of-contents ul { + margin: 1em; + list-style: none; +} + +.table-of-contents ul ul { + margin-top: 0.25em; +} + +.table-of-contents ul :link, +.table-of-contents ul :visited { + font-size: 16px; +} + +.table-of-contents li { + margin-bottom: 0.25em; +} + +.table-of-contents li .toc-toggle { + width: 16px; + height: 16px; + background: url(images/add.png) no-repeat; +} + +.table-of-contents li .toc-toggle.open { + background: url(images/delete.png) no-repeat; +} + +/* @end */ + +/* @group Top-Level Structure */ + +nav { + float: left; + width: 260px; + font-family: Helvetica, sans-serif; + font-size: 14px; +} + +main { + display: block; + margin: 0 2em 5em 260px; + padding-left: 20px; + min-width: 340px; + font-size: 16px; +} + +main h1, +main h2, +main h3, +main h4, +main h5, +main h6 { + font-family: Helvetica, sans-serif; +} + +.table-of-contents main { + margin-left: 2em; +} + +#validator-badges { + clear: both; + margin: 1em 1em 2em; + font-size: smaller; +} + +/* @end */ + +/* @group navigation */ +nav { + margin-bottom: 1em; +} + +nav .nav-section { + margin-top: 2em; + border-top: 2px solid #aaa; + font-size: 90%; + overflow: hidden; +} + +nav h2 { + margin: 0; + padding: 2px 8px 2px 8px; + background-color: #e8e8e8; + color: #555; + font-size: 125%; + text-align: center; +} + +nav h3, +#table-of-contents-navigation { + margin: 0; + padding: 2px 8px 2px 8px; + text-align: right; + background-color: #e8e8e8; + color: #555; +} + +nav ul, +nav dl, +nav p { + padding: 4px 8px 0; + list-style: none; +} + +#project-navigation .nav-section { + margin: 0; + border-top: 0; +} + +#home-section h2 { + text-align: center; +} + +#table-of-contents-navigation { + font-size: 1.2em; + font-weight: bold; + text-align: center; +} + +#search-section { + margin-top: 0; + border-top: 0; +} + +#search-field-wrapper { + border-top: 1px solid #aaa; + border-bottom: 1px solid #aaa; + padding: 3px 8px; + background-color: #e8e8e8; + color: #555; +} + +ul.link-list li { + white-space: nowrap; + line-height: 1.4em; +} + +ul.link-list .type { + font-size: 8px; + text-transform: uppercase; + color: white; + background: #969696; + padding: 2px 4px; + -webkit-border-radius: 5px; +} + +.calls-super { + background: url(images/arrow_up.png) no-repeat right center; +} + +/* @end */ + +/* @group Documentation Section */ +main { + color: #333; +} + +main > h1:first-child, +main > h2:first-child, +main > h3:first-child, +main > h4:first-child, +main > h5:first-child, +main > h6:first-child { + margin-top: 0px; +} + +main sup { + vertical-align: super; + font-size: 0.8em; +} + +/* The heading with the class name */ +main h1[class] { + margin-top: 0; + margin-bottom: 1em; + font-size: 2em; + color: #6C8C22; +} + +main h1 { + margin: 2em 0 0.5em; + font-size: 1.7em; +} + +main h2 { + margin: 2em 0 0.5em; + font-size: 1.5em; +} + +main h3 { + margin: 2em 0 0.5em; + font-size: 1.2em; +} + +main h4 { + margin: 2em 0 0.5em; + font-size: 1.1em; +} + +main h5 { + margin: 2em 0 0.5em; + font-size: 1em; +} + +main h6 { + margin: 2em 0 0.5em; + font-size: 1em; +} + +main p { + margin: 0 0 0.5em; + line-height: 1.4em; +} + +main pre { + margin: 1.2em 0.5em; + padding: 1em; + font-size: 0.8em; +} + +main hr { + margin: 1.5em 1em; + border: 2px solid #ddd; +} + +main blockquote { + margin: 0 2em 1.2em 1.2em; + padding-left: 0.5em; + border-left: 2px solid #ddd; +} + +main ol, +main ul { + margin: 1em 2em; +} + +main li > p { + margin-bottom: 0.5em; +} + +main dl { + margin: 1em 0.5em; +} + +main dt { + margin-bottom: 0.5em; + font-weight: bold; +} + +main dd { + margin: 0 1em 1em 0.5em; +} + +main header h2 { + margin-top: 2em; + border-width: 0; + border-top: 4px solid #bbb; + font-size: 130%; +} + +main header h3 { + margin: 2em 0 1.5em; + border-width: 0; + border-top: 3px solid #bbb; + font-size: 120%; +} + +.documentation-section-title { + position: relative; +} +.documentation-section-title .section-click-top { + position: absolute; + top: 6px; + left: 12px; + font-size: 10px; + color: #9b9877; + visibility: hidden; + padding-left: 0.5px; +} + +.documentation-section-title:hover .section-click-top { + visibility: visible; +} + +.constants-list > dl { + margin: 1em 0 2em; + border: 0; +} + +.constants-list > dl dt { + margin-bottom: 0.75em; + padding-left: 0; + font-family: "Source Code Pro", Monaco, monospace; + font-size: 110%; +} + +.constants-list > dl dt a { + color: inherit; +} + +.constants-list > dl dd { + margin: 0 0 2em 0; + padding: 0; + color: #666; +} + +.documentation-section h2 { + position: relative; +} + +.documentation-section h2 a { + position: absolute; + top: 8px; + right: 10px; + font-size: 12px; + color: #9b9877; + visibility: hidden; +} + +.documentation-section h2:hover a { + visibility: visible; +} + +/* @group Method Details */ + +main .method-source-code { + display: none; +} + +main .method-description .method-calls-super { + color: #333; + font-weight: bold; +} + +main .method-detail { + margin-bottom: 2.5em; + cursor: pointer; +} + +main .method-detail:target { + margin-left: -10px; + border-left: 10px solid #f1edba; +} + +main .method-heading { + position: relative; + font-family: "Source Code Pro", Monaco, monospace; + font-size: 110%; + font-weight: bold; + color: #333; +} +main .method-heading :link, +main .method-heading :visited { + color: inherit; +} +main .method-click-advice { + position: absolute; + top: 2px; + right: 5px; + font-size: 12px; + color: #9b9877; + visibility: hidden; + padding-right: 20px; + line-height: 20px; + background: url(images/zoom.png) no-repeat right top; +} +main .method-heading:hover .method-click-advice { + visibility: visible; +} + +main .method-alias .method-heading { + color: #666; +} + +main .method-description, +main .aliases { + margin-top: 0.75em; + color: #333; +} + +main .aliases { + padding-top: 4px; + font-style: italic; + cursor: default; +} +main .method-description ul { + margin-left: 1.5em; +} + +main #attribute-method-details .method-detail:hover { + background-color: transparent; + cursor: default; +} +main .attribute-access-type { + text-transform: uppercase; + padding: 0 1em; +} +/* @end */ + +/* @end */ + +/* @group Source Code */ + +pre { + margin: 0.5em 0; + border: 1px dashed #999; + padding: 0.5em; + background: #262626; + color: white; + overflow: auto; +} + +.ruby-constant { color: #7fffd4; background: transparent; } +.ruby-keyword { color: #00ffff; background: transparent; } +.ruby-ivar { color: #eedd82; background: transparent; } +.ruby-operator { color: #00ffee; background: transparent; } +.ruby-identifier { color: #ffdead; background: transparent; } +.ruby-node { color: #ffa07a; background: transparent; } +.ruby-comment { color: #dc0000; background: transparent; } +.ruby-regexp { color: #ffa07a; background: transparent; } +.ruby-value { color: #7fffd4; background: transparent; } + +/* @end */ + + +/* @group search results */ +#search-results { + font-family: Lato, sans-serif; + font-weight: 300; +} + +#search-results .search-match { + font-family: Helvetica, sans-serif; + font-weight: normal; +} + +#search-results .search-selected { + background: #e8e8e8; + border-bottom: 1px solid transparent; +} + +#search-results li { + list-style: none; + border-bottom: 1px solid #aaa; + margin-bottom: 0.5em; +} + +#search-results li:last-child { + border-bottom: none; + margin-bottom: 0; +} + +#search-results li p { + padding: 0; + margin: 0.5em; +} + +#search-results .search-namespace { + font-weight: bold; +} + +#search-results li em { + background: yellow; + font-style: normal; +} + +#search-results pre { + margin: 0.5em; + font-family: "Source Code Pro", Monaco, monospace; +} + +/* @end */ + diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/fonts/Lato-Light.ttf b/jni/ruby/lib/rdoc/generator/template/darkfish/fonts/Lato-Light.ttf Binary files differnew file mode 100644 index 0000000..b49dd43 --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/fonts/Lato-Light.ttf diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/fonts/Lato-LightItalic.ttf b/jni/ruby/lib/rdoc/generator/template/darkfish/fonts/Lato-LightItalic.ttf Binary files differnew file mode 100644 index 0000000..7959fef --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/fonts/Lato-LightItalic.ttf diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/fonts/Lato-Regular.ttf b/jni/ruby/lib/rdoc/generator/template/darkfish/fonts/Lato-Regular.ttf Binary files differnew file mode 100644 index 0000000..839cd58 --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/fonts/Lato-Regular.ttf diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/fonts/Lato-RegularItalic.ttf b/jni/ruby/lib/rdoc/generator/template/darkfish/fonts/Lato-RegularItalic.ttf Binary files differnew file mode 100644 index 0000000..bababa0 --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/fonts/Lato-RegularItalic.ttf diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/fonts/SourceCodePro-Bold.ttf b/jni/ruby/lib/rdoc/generator/template/darkfish/fonts/SourceCodePro-Bold.ttf Binary files differnew file mode 100644 index 0000000..61e3090 --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/fonts/SourceCodePro-Bold.ttf diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/fonts/SourceCodePro-Regular.ttf b/jni/ruby/lib/rdoc/generator/template/darkfish/fonts/SourceCodePro-Regular.ttf Binary files differnew file mode 100644 index 0000000..85686d9 --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/fonts/SourceCodePro-Regular.ttf diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/images/add.png b/jni/ruby/lib/rdoc/generator/template/darkfish/images/add.png Binary files differnew file mode 100644 index 0000000..6332fef --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/images/add.png diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/images/arrow_up.png b/jni/ruby/lib/rdoc/generator/template/darkfish/images/arrow_up.png Binary files differnew file mode 100644 index 0000000..1ebb193 --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/images/arrow_up.png diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/images/brick.png b/jni/ruby/lib/rdoc/generator/template/darkfish/images/brick.png Binary files differnew file mode 100644 index 0000000..7851cf3 --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/images/brick.png diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/images/brick_link.png b/jni/ruby/lib/rdoc/generator/template/darkfish/images/brick_link.png Binary files differnew file mode 100644 index 0000000..9ebf013 --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/images/brick_link.png diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/images/bug.png b/jni/ruby/lib/rdoc/generator/template/darkfish/images/bug.png Binary files differnew file mode 100644 index 0000000..2d5fb90 --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/images/bug.png diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/images/bullet_black.png b/jni/ruby/lib/rdoc/generator/template/darkfish/images/bullet_black.png Binary files differnew file mode 100644 index 0000000..5761970 --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/images/bullet_black.png diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/images/bullet_toggle_minus.png b/jni/ruby/lib/rdoc/generator/template/darkfish/images/bullet_toggle_minus.png Binary files differnew file mode 100644 index 0000000..b47ce55 --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/images/bullet_toggle_minus.png diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/images/bullet_toggle_plus.png b/jni/ruby/lib/rdoc/generator/template/darkfish/images/bullet_toggle_plus.png Binary files differnew file mode 100644 index 0000000..9ab4a89 --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/images/bullet_toggle_plus.png diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/images/date.png b/jni/ruby/lib/rdoc/generator/template/darkfish/images/date.png Binary files differnew file mode 100644 index 0000000..783c833 --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/images/date.png diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/images/delete.png b/jni/ruby/lib/rdoc/generator/template/darkfish/images/delete.png Binary files differnew file mode 100644 index 0000000..08f2493 --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/images/delete.png diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/images/find.png b/jni/ruby/lib/rdoc/generator/template/darkfish/images/find.png Binary files differnew file mode 100644 index 0000000..1547479 --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/images/find.png diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/images/loadingAnimation.gif b/jni/ruby/lib/rdoc/generator/template/darkfish/images/loadingAnimation.gif Binary files differnew file mode 100644 index 0000000..82290f4 --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/images/loadingAnimation.gif diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/images/macFFBgHack.png b/jni/ruby/lib/rdoc/generator/template/darkfish/images/macFFBgHack.png Binary files differnew file mode 100644 index 0000000..c6473b3 --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/images/macFFBgHack.png diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/images/package.png b/jni/ruby/lib/rdoc/generator/template/darkfish/images/package.png Binary files differnew file mode 100644 index 0000000..da3c2a2 --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/images/package.png diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/images/page_green.png b/jni/ruby/lib/rdoc/generator/template/darkfish/images/page_green.png Binary files differnew file mode 100644 index 0000000..de8e003 --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/images/page_green.png diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/images/page_white_text.png b/jni/ruby/lib/rdoc/generator/template/darkfish/images/page_white_text.png Binary files differnew file mode 100644 index 0000000..813f712 --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/images/page_white_text.png diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/images/page_white_width.png b/jni/ruby/lib/rdoc/generator/template/darkfish/images/page_white_width.png Binary files differnew file mode 100644 index 0000000..1eb8809 --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/images/page_white_width.png diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/images/plugin.png b/jni/ruby/lib/rdoc/generator/template/darkfish/images/plugin.png Binary files differnew file mode 100644 index 0000000..6187b15 --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/images/plugin.png diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/images/ruby.png b/jni/ruby/lib/rdoc/generator/template/darkfish/images/ruby.png Binary files differnew file mode 100644 index 0000000..f763a16 --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/images/ruby.png diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/images/tag_blue.png b/jni/ruby/lib/rdoc/generator/template/darkfish/images/tag_blue.png Binary files differnew file mode 100644 index 0000000..3f02b5f --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/images/tag_blue.png diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/images/tag_green.png b/jni/ruby/lib/rdoc/generator/template/darkfish/images/tag_green.png Binary files differnew file mode 100644 index 0000000..83ec984 --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/images/tag_green.png diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/images/transparent.png b/jni/ruby/lib/rdoc/generator/template/darkfish/images/transparent.png Binary files differnew file mode 100644 index 0000000..d665e17 --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/images/transparent.png diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/images/wrench.png b/jni/ruby/lib/rdoc/generator/template/darkfish/images/wrench.png Binary files differnew file mode 100644 index 0000000..5c8213f --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/images/wrench.png diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/images/wrench_orange.png b/jni/ruby/lib/rdoc/generator/template/darkfish/images/wrench_orange.png Binary files differnew file mode 100644 index 0000000..565a933 --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/images/wrench_orange.png diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/images/zoom.png b/jni/ruby/lib/rdoc/generator/template/darkfish/images/zoom.png Binary files differnew file mode 100644 index 0000000..908612e --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/images/zoom.png diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/index.rhtml b/jni/ruby/lib/rdoc/generator/template/darkfish/index.rhtml new file mode 100644 index 0000000..7d1c748 --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/index.rhtml @@ -0,0 +1,23 @@ +<body id="top" role="document" class="file"> +<nav role="navigation"> + <div id="project-navigation"> + <%= render '_sidebar_navigation.rhtml' %> + + <%= render '_sidebar_search.rhtml' %> + </div> + + <div id="project-metadata"> + <%= render '_sidebar_pages.rhtml' %> + <%= render '_sidebar_classes.rhtml' %> + </div> +</nav> + +<main role="main"> +<% if @options.main_page and + main_page = @files.find { |f| f.full_name == @options.main_page } then %> +<%= main_page.description %> +<% else %> +<p>This is the API documentation for <%= @title %>. +<% end %> +</main> + diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/js/darkfish.js b/jni/ruby/lib/rdoc/generator/template/darkfish/js/darkfish.js new file mode 100644 index 0000000..b789a65 --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/js/darkfish.js @@ -0,0 +1,161 @@ +/** + * + * Darkfish Page Functions + * $Id: darkfish.js 53 2009-01-07 02:52:03Z deveiant $ + * + * Author: Michael Granger <mgranger@laika.com> + * + */ + +/* Provide console simulation for firebug-less environments */ +if (!("console" in window) || !("firebug" in console)) { + var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml", + "group", "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd"]; + + window.console = {}; + for (var i = 0; i < names.length; ++i) + window.console[names[i]] = function() {}; +}; + + +/** + * Unwrap the first element that matches the given @expr@ from the targets and return them. + */ +$.fn.unwrap = function( expr ) { + return this.each( function() { + $(this).parents( expr ).eq( 0 ).after( this ).remove(); + }); +}; + + +function showSource( e ) { + var target = e.target; + var codeSections = $(target). + parents('.method-detail'). + find('.method-source-code'); + + $(target). + parents('.method-detail'). + find('.method-source-code'). + slideToggle(); +}; + +function hookSourceViews() { + $('.method-heading').click( showSource ); +}; + +function hookSearch() { + var input = $('#search-field').eq(0); + var result = $('#search-results').eq(0); + $(result).show(); + + var search_section = $('#search-section').get(0); + $(search_section).show(); + + var search = new Search(search_data, input, result); + + search.renderItem = function(result) { + var li = document.createElement('li'); + var html = ''; + + // TODO add relative path to <script> per-page + html += '<p class="search-match"><a href="' + rdoc_rel_prefix + result.path + '">' + this.hlt(result.title); + if (result.params) + html += '<span class="params">' + result.params + '</span>'; + html += '</a>'; + + + if (result.namespace) + html += '<p class="search-namespace">' + this.hlt(result.namespace); + + if (result.snippet) + html += '<div class="search-snippet">' + result.snippet + '</div>'; + + li.innerHTML = html; + + return li; + } + + search.select = function(result) { + var result_element = result.get(0); + window.location.href = result_element.firstChild.firstChild.href; + } + + search.scrollIntoView = search.scrollInWindow; +}; + +function highlightTarget( anchor ) { + console.debug( "Highlighting target '%s'.", anchor ); + + $("a[name]").each( function() { + if ( $(this).attr("name") == anchor ) { + if ( !$(this).parent().parent().hasClass('target-section') ) { + console.debug( "Wrapping the target-section" ); + $('div.method-detail').unwrap( 'div.target-section' ); + $(this).parent().wrap( '<div class="target-section"></div>' ); + } else { + console.debug( "Already wrapped." ); + } + } + }); +}; + +function highlightLocationTarget() { + console.debug( "Location hash: %s", window.location.hash ); + if ( ! window.location.hash || window.location.hash.length == 0 ) return; + + var anchor = window.location.hash.substring(1); + console.debug( "Found anchor: %s; matching %s", anchor, "a[name=" + anchor + "]" ); + + highlightTarget( anchor ); +}; + +function highlightClickTarget( event ) { + console.debug( "Highlighting click target for event %o", event.target ); + try { + var anchor = $(event.target).attr( 'href' ).substring(1); + console.debug( "Found target anchor: %s", anchor ); + highlightTarget( anchor ); + } catch ( err ) { + console.error( "Exception while highlighting: %o", err ); + }; +}; + +function loadAsync(path, success) { + $.ajax({ + url: rdoc_rel_prefix + path, + dataType: 'script', + success: success, + cache: true + }); +}; + +$(document).ready( function() { + hookSourceViews(); + highlightLocationTarget(); + $('ul.link-list a').bind( "click", highlightClickTarget ); + + var search_scripts_loaded = { + navigation_loaded: false, + search_loaded: false, + search_index_loaded: false, + searcher_loaded: false, + } + + var search_success_function = function(variable) { + return (function (data, status, xhr) { + search_scripts_loaded[variable] = true; + + if (search_scripts_loaded['navigation_loaded'] == true && + search_scripts_loaded['search_loaded'] == true && + search_scripts_loaded['search_index_loaded'] == true && + search_scripts_loaded['searcher_loaded'] == true) + hookSearch(); + }); + } + + loadAsync('js/navigation.js', search_success_function('navigation_loaded')); + loadAsync('js/search.js', search_success_function('search_loaded')); + loadAsync('js/search_index.js', search_success_function('search_index_loaded')); + loadAsync('js/searcher.js', search_success_function('searcher_loaded')); +}); diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/js/jquery.js b/jni/ruby/lib/rdoc/generator/template/darkfish/js/jquery.js new file mode 100644 index 0000000..628ed9b --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/js/jquery.js @@ -0,0 +1,4 @@ +/*! jQuery v1.6.4 http://jquery.com/ | http://jquery.org/license */ +(function(a,b){function cu(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cr(a){if(!cg[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){ch||(ch=c.createElement("iframe"),ch.frameBorder=ch.width=ch.height=0),b.appendChild(ch);if(!ci||!ch.createElement)ci=(ch.contentWindow||ch.contentDocument).document,ci.write((c.compatMode==="CSS1Compat"?"<!doctype html>":"")+"<html><body>"),ci.close();d=ci.createElement(a),ci.body.appendChild(d),e=f.css(d,"display"),b.removeChild(ch)}cg[a]=e}return cg[a]}function cq(a,b){var c={};f.each(cm.concat.apply([],cm.slice(0,b)),function(){c[this]=a});return c}function cp(){cn=b}function co(){setTimeout(cp,0);return cn=f.now()}function cf(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ce(){try{return new a.XMLHttpRequest}catch(b){}}function b$(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g<i;g++){if(g===1)for(h in a.converters)typeof h=="string"&&(e[h.toLowerCase()]=a.converters[h]);l=k,k=d[g];if(k==="*")k=l;else if(l!=="*"&&l!==k){m=l+" "+k,n=e[m]||e["* "+k];if(!n){p=b;for(o in e){j=o.split(" ");if(j[0]===l||j[0]==="*"){p=e[j[1]+" "+k];if(p){o=e[o],o===!0?n=p:p===!0&&(n=o);break}}}}!n&&!p&&f.error("No conversion from "+m.replace(" "," to ")),n!==!0&&(c=n?n(c):p(o(c)))}}return c}function bZ(a,c,d){var e=a.contents,f=a.dataTypes,g=a.responseFields,h,i,j,k;for(i in g)i in d&&(c[g[i]]=d[i]);while(f[0]==="*")f.shift(),h===b&&(h=a.mimeType||c.getResponseHeader("content-type"));if(h)for(i in e)if(e[i]&&e[i].test(h)){f.unshift(i);break}if(f[0]in d)j=f[0];else{for(i in d){if(!f[0]||a.converters[i+" "+f[0]]){j=i;break}k||(k=i)}j=j||k}if(j){j!==f[0]&&f.unshift(j);return d[j]}}function bY(a,b,c,d){if(f.isArray(b))f.each(b,function(b,e){c||bA.test(a)?d(a,e):bY(a+"["+(typeof e=="object"||f.isArray(e)?b:"")+"]",e,c,d)});else if(!c&&b!=null&&typeof b=="object")for(var e in b)bY(a+"["+e+"]",b[e],c,d);else d(a,b)}function bX(a,c){var d,e,g=f.ajaxSettings.flatOptions||{};for(d in c)c[d]!==b&&((g[d]?a:e||(e={}))[d]=c[d]);e&&f.extend(!0,a,e)}function bW(a,c,d,e,f,g){f=f||c.dataTypes[0],g=g||{},g[f]=!0;var h=a[f],i=0,j=h?h.length:0,k=a===bP,l;for(;i<j&&(k||!l);i++)l=h[i](c,d,e),typeof l=="string"&&(!k||g[l]?l=b:(c.dataTypes.unshift(l),l=bW(a,c,d,e,l,g)));(k||!l)&&!g["*"]&&(l=bW(a,c,d,e,"*",g));return l}function bV(a){return function(b,c){typeof b!="string"&&(c=b,b="*");if(f.isFunction(c)){var d=b.toLowerCase().split(bL),e=0,g=d.length,h,i,j;for(;e<g;e++)h=d[e],j=/^\+/.test(h),j&&(h=h.substr(1)||"*"),i=a[h]=a[h]||[],i[j?"unshift":"push"](c)}}}function by(a,b,c){var d=b==="width"?a.offsetWidth:a.offsetHeight,e=b==="width"?bt:bu;if(d>0){c!=="border"&&f.each(e,function(){c||(d-=parseFloat(f.css(a,"padding"+this))||0),c==="margin"?d+=parseFloat(f.css(a,c+this))||0:d-=parseFloat(f.css(a,"border"+this+"Width"))||0});return d+"px"}d=bv(a,b,b);if(d<0||d==null)d=a.style[b]||0;d=parseFloat(d)||0,c&&f.each(e,function(){d+=parseFloat(f.css(a,"padding"+this))||0,c!=="padding"&&(d+=parseFloat(f.css(a,"border"+this+"Width"))||0),c==="margin"&&(d+=parseFloat(f.css(a,c+this))||0)});return d+"px"}function bl(a,b){b.src?f.ajax({url:b.src,async:!1,dataType:"script"}):f.globalEval((b.text||b.textContent||b.innerHTML||"").replace(bd,"/*$0*/")),b.parentNode&&b.parentNode.removeChild(b)}function bk(a){f.nodeName(a,"input")?bj(a):"getElementsByTagName"in a&&f.grep(a.getElementsByTagName("input"),bj)}function bj(a){if(a.type==="checkbox"||a.type==="radio")a.defaultChecked=a.checked}function bi(a){return"getElementsByTagName"in a?a.getElementsByTagName("*"):"querySelectorAll"in a?a.querySelectorAll("*"):[]}function bh(a,b){var c;if(b.nodeType===1){b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase();if(c==="object")b.outerHTML=a.outerHTML;else if(c!=="input"||a.type!=="checkbox"&&a.type!=="radio"){if(c==="option")b.selected=a.defaultSelected;else if(c==="input"||c==="textarea")b.defaultValue=a.defaultValue}else a.checked&&(b.defaultChecked=b.checked=a.checked),b.value!==a.value&&(b.value=a.value);b.removeAttribute(f.expando)}}function bg(a,b){if(b.nodeType===1&&!!f.hasData(a)){var c=f.expando,d=f.data(a),e=f.data(b,d);if(d=d[c]){var g=d.events;e=e[c]=f.extend({},d);if(g){delete e.handle,e.events={};for(var h in g)for(var i=0,j=g[h].length;i<j;i++)f.event.add(b,h+(g[h][i].namespace?".":"")+g[h][i].namespace,g[h][i],g[h][i].data)}}}}function bf(a,b){return f.nodeName(a,"table")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function V(a,b,c){b=b||0;if(f.isFunction(b))return f.grep(a,function(a,d){var e=!!b.call(a,d,a);return e===c});if(b.nodeType)return f.grep(a,function(a,d){return a===b===c});if(typeof b=="string"){var d=f.grep(a,function(a){return a.nodeType===1});if(Q.test(b))return f.filter(b,d,!c);b=f.filter(b,d)}return f.grep(a,function(a,d){return f.inArray(a,b)>=0===c})}function U(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function M(a,b){return(a&&a!=="*"?a+".":"")+b.replace(y,"`").replace(z,"&")}function L(a){var b,c,d,e,g,h,i,j,k,l,m,n,o,p=[],q=[],r=f._data(this,"events");if(!(a.liveFired===this||!r||!r.live||a.target.disabled||a.button&&a.type==="click")){a.namespace&&(n=new RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)")),a.liveFired=this;var s=r.live.slice(0);for(i=0;i<s.length;i++)g=s[i],g.origType.replace(w,"")===a.type?q.push(g.selector):s.splice(i--,1);e=f(a.target).closest(q,a.currentTarget);for(j=0,k=e.length;j<k;j++){m=e[j];for(i=0;i<s.length;i++){g=s[i];if(m.selector===g.selector&&(!n||n.test(g.namespace))&&!m.elem.disabled){h=m.elem,d=null;if(g.preType==="mouseenter"||g.preType==="mouseleave")a.type=g.preType,d=f(a.relatedTarget).closest(g.selector)[0],d&&f.contains(h,d)&&(d=h);(!d||d!==h)&&p.push({elem:h,handleObj:g,level:m.level})}}}for(j=0,k=p.length;j<k;j++){e=p[j];if(c&&e.level>c)break;a.currentTarget=e.elem,a.data=e.handleObj.data,a.handleObj=e.handleObj,o=e.handleObj.origHandler.apply(e.elem,arguments);if(o===!1||a.isPropagationStopped()){c=e.level,o===!1&&(b=!1);if(a.isImmediatePropagationStopped())break}}return b}}function J(a,c,d){var e=f.extend({},d[0]);e.type=a,e.originalEvent={},e.liveFired=b,f.event.handle.call(c,e),e.isDefaultPrevented()&&d[0].preventDefault()}function D(){return!0}function C(){return!1}function m(a,c,d){var e=c+"defer",g=c+"queue",h=c+"mark",i=f.data(a,e,b,!0);i&&(d==="queue"||!f.data(a,g,b,!0))&&(d==="mark"||!f.data(a,h,b,!0))&&setTimeout(function(){!f.data(a,g,b,!0)&&!f.data(a,h,b,!0)&&(f.removeData(a,e,!0),i.resolve())},0)}function l(a){for(var b in a)if(b!=="toJSON")return!1;return!0}function k(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(j,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNaN(d)?i.test(d)?f.parseJSON(d):d:parseFloat(d)}catch(g){}f.data(a,c,d)}else d=b}return d}var c=a.document,d=a.navigator,e=a.location,f=function(){function K(){if(!e.isReady){try{c.documentElement.doScroll("left")}catch(a){setTimeout(K,1);return}e.ready()}}var e=function(a,b){return new e.fn.init(a,b,h)},f=a.jQuery,g=a.$,h,i=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/\d/,n=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,o=/^[\],:{}\s]*$/,p=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,q=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,r=/(?:^|:|,)(?:\s*\[)+/g,s=/(webkit)[ \/]([\w.]+)/,t=/(opera)(?:.*version)?[ \/]([\w.]+)/,u=/(msie) ([\w.]+)/,v=/(mozilla)(?:.*? rv:([\w.]+))?/,w=/-([a-z]|[0-9])/ig,x=/^-ms-/,y=function(a,b){return(b+"").toUpperCase()},z=d.userAgent,A,B,C,D=Object.prototype.toString,E=Object.prototype.hasOwnProperty,F=Array.prototype.push,G=Array.prototype.slice,H=String.prototype.trim,I=Array.prototype.indexOf,J={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=n.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.6.4",length:0,size:function(){return this.length},toArray:function(){return G.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?F.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),B.done(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(G.apply(this,arguments),"slice",G.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:F,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j<k;j++)if((a=arguments[j])!=null)for(c in a){d=i[c],f=a[c];if(i===f)continue;l&&f&&(e.isPlainObject(f)||(g=e.isArray(f)))?(g?(g=!1,h=d&&e.isArray(d)?d:[]):h=d&&e.isPlainObject(d)?d:{},i[c]=e.extend(l,h,f)):f!==b&&(i[c]=f)}return i},e.extend({noConflict:function(b){a.$===e&&(a.$=g),b&&a.jQuery===e&&(a.jQuery=f);return e},isReady:!1,readyWait:1,holdReady:function(a){a?e.readyWait++:e.ready(!0)},ready:function(a){if(a===!0&&!--e.readyWait||a!==!0&&!e.isReady){if(!c.body)return setTimeout(e.ready,1);e.isReady=!0;if(a!==!0&&--e.readyWait>0)return;B.resolveWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").unbind("ready")}},bindReady:function(){if(!B){B=e._Deferred();if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",C,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",C),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&K()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNaN:function(a){return a==null||!m.test(a)||isNaN(a)},type:function(a){return a==null?String(a):J[D.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!E.call(a,"constructor")&&!E.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||E.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw a},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(o.test(b.replace(p,"@").replace(q,"]").replace(r,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(c){var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&e.error("Invalid XML: "+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(x,"ms-").replace(w,y)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g<h;)if(c.apply(a[g++],d)===!1)break}else if(i){for(f in a)if(c.call(a[f],f,a[f])===!1)break}else for(;g<h;)if(c.call(a[g],g,a[g++])===!1)break;return a},trim:H?function(a){return a==null?"":H.call(a)}:function(a){return a==null?"":(a+"").replace(k,"").replace(l,"")},makeArray:function(a,b){var c=b||[];if(a!=null){var d=e.type(a);a.length==null||d==="string"||d==="function"||d==="regexp"||e.isWindow(a)?F.call(c,a):e.merge(c,a)}return c},inArray:function(a,b){if(!b)return-1;if(I)return I.call(b,a);for(var c=0,d=b.length;c<d;c++)if(b[c]===a)return c;return-1},merge:function(a,c){var d=a.length,e=0;if(typeof c.length=="number")for(var f=c.length;e<f;e++)a[d++]=c[e];else while(c[e]!==b)a[d++]=c[e++];a.length=d;return a},grep:function(a,b,c){var d=[],e;c=!!c;for(var f=0,g=a.length;f<g;f++)e=!!b(a[f],f),c!==e&&d.push(a[f]);return d},map:function(a,c,d){var f,g,h=[],i=0,j=a.length,k=a instanceof e||j!==b&&typeof j=="number"&&(j>0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i<j;i++)f=c(a[i],i,d),f!=null&&(h[h.length]=f);else for(g in a)f=c(a[g],g,d),f!=null&&(h[h.length]=f);return h.concat.apply([],h)},guid:1,proxy:function(a,c){if(typeof c=="string"){var d=a[c];c=a,a=d}if(!e.isFunction(a))return b;var f=G.call(arguments,2),g=function(){return a.apply(c,f.concat(G.call(arguments)))};g.guid=a.guid=a.guid||g.guid||e.guid++;return g},access:function(a,c,d,f,g,h){var i=a.length;if(typeof c=="object"){for(var j in c)e.access(a,j,c[j],f,g,d);return a}if(d!==b){f=!h&&f&&e.isFunction(d);for(var k=0;k<i;k++)g(a[k],c,f?d.call(a[k],k,g(a[k],c)):d,h);return a}return i?g(a[0],c):b},now:function(){return(new Date).getTime()},uaMatch:function(a){a=a.toLowerCase();var b=s.exec(a)||t.exec(a)||u.exec(a)||a.indexOf("compatible")<0&&v.exec(a)||[];return{browser:b[1]||"",version:b[2]||"0"}},sub:function(){function a(b,c){return new a.fn.init(b,c)}e.extend(!0,a,this),a.superclass=this,a.fn=a.prototype=this(),a.fn.constructor=a,a.sub=this.sub,a.fn.init=function(d,f){f&&f instanceof e&&!(f instanceof a)&&(f=a(f));return e.fn.init.call(this,d,f,b)},a.fn.init.prototype=a.fn;var b=a(c);return a},browser:{}}),e.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(a,b){J["[object "+b+"]"]=b.toLowerCase()}),A=e.uaMatch(z),A.browser&&(e.browser[A.browser]=!0,e.browser.version=A.version),e.browser.webkit&&(e.browser.safari=!0),j.test(" ")&&(k=/^[\s\xA0]+/,l=/[\s\xA0]+$/),h=e(c),c.addEventListener?C=function(){c.removeEventListener("DOMContentLoaded",C,!1),e.ready()}:c.attachEvent&&(C=function(){c.readyState==="complete"&&(c.detachEvent("onreadystatechange",C),e.ready())});return e}(),g="done fail isResolved isRejected promise then always pipe".split(" "),h=[].slice;f.extend({_Deferred:function(){var a=[],b,c,d,e={done:function(){if(!d){var c=arguments,g,h,i,j,k;b&&(k=b,b=0);for(g=0,h=c.length;g<h;g++)i=c[g],j=f.type(i),j==="array"?e.done.apply(e,i):j==="function"&&a.push(i);k&&e.resolveWith(k[0],k[1])}return this},resolveWith:function(e,f){if(!d&&!b&&!c){f=f||[],c=1;try{while(a[0])a.shift().apply(e,f)}finally{b=[e,f],c=0}}return this},resolve:function(){e.resolveWith(this,arguments);return this},isResolved:function(){return!!c||!!b},cancel:function(){d=1,a=[];return this}};return e},Deferred:function(a){var b=f._Deferred(),c=f._Deferred(),d;f.extend(b,{then:function(a,c){b.done(a).fail(c);return this},always:function(){return b.done.apply(b,arguments).fail.apply(this,arguments)},fail:c.done,rejectWith:c.resolveWith,reject:c.resolve,isRejected:c.isResolved,pipe:function(a,c){return f.Deferred(function(d){f.each({done:[a,"resolve"],fail:[c,"reject"]},function(a,c){var e=c[0],g=c[1],h;f.isFunction(e)?b[a](function(){h=e.apply(this,arguments),h&&f.isFunction(h.promise)?h.promise().then(d.resolve,d.reject):d[g+"With"](this===b?d:this,[h])}):b[a](d[g])})}).promise()},promise:function(a){if(a==null){if(d)return d;d=a={}}var c=g.length;while(c--)a[g[c]]=b[g[c]];return a}}),b.done(c.cancel).fail(b.cancel),delete b.cancel,a&&a.call(b,b);return b},when:function(a){function i(a){return function(c){b[a]=arguments.length>1?h.call(arguments,0):c,--e||g.resolveWith(g,h.call(b,0))}}var b=arguments,c=0,d=b.length,e=d,g=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred();if(d>1){for(;c<d;c++)b[c]&&f.isFunction(b[c].promise)?b[c].promise().then(i(c),g.reject):--e;e||g.resolveWith(g,b)}else g!==a&&g.resolveWith(g,d?[a]:[]);return g.promise()}}),f.support=function(){var a=c.createElement("div"),b=c.documentElement,d,e,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u;a.setAttribute("className","t"),a.innerHTML=" <link/><table></table><a href='/a' style='top:1px;float:left;opacity:.55;'>a</a><input type='checkbox'/>",d=a.getElementsByTagName("*"),e=a.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=a.getElementsByTagName("input")[0],k={leadingWhitespace:a.firstChild.nodeType===3,tbody:!a.getElementsByTagName("tbody").length,htmlSerialize:!!a.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55$/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:a.className!=="t",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},i.checked=!0,k.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,k.optDisabled=!h.disabled;try{delete a.test}catch(v){k.deleteExpando=!1}!a.addEventListener&&a.attachEvent&&a.fireEvent&&(a.attachEvent("onclick",function(){k.noCloneEvent=!1}),a.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),k.radioValue=i.value==="t",i.setAttribute("checked","checked"),a.appendChild(i),l=c.createDocumentFragment(),l.appendChild(a.firstChild),k.checkClone=l.cloneNode(!0).cloneNode(!0).lastChild.checked,a.innerHTML="",a.style.width=a.style.paddingLeft="1px",m=c.getElementsByTagName("body")[0],o=c.createElement(m?"div":"body"),p={visibility:"hidden",width:0,height:0,border:0,margin:0,background:"none"},m&&f.extend(p,{position:"absolute",left:"-1000px",top:"-1000px"});for(t in p)o.style[t]=p[t];o.appendChild(a),n=m||b,n.insertBefore(o,n.firstChild),k.appendChecked=i.checked,k.boxModel=a.offsetWidth===2,"zoom"in a.style&&(a.style.display="inline",a.style.zoom=1,k.inlineBlockNeedsLayout=a.offsetWidth===2,a.style.display="",a.innerHTML="<div style='width:4px;'></div>",k.shrinkWrapBlocks=a.offsetWidth!==2),a.innerHTML="<table><tr><td style='padding:0;border:0;display:none'></td><td>t</td></tr></table>",q=a.getElementsByTagName("td"),u=q[0].offsetHeight===0,q[0].style.display="",q[1].style.display="none",k.reliableHiddenOffsets=u&&q[0].offsetHeight===0,a.innerHTML="",c.defaultView&&c.defaultView.getComputedStyle&&(j=c.createElement("div"),j.style.width="0",j.style.marginRight="0",a.appendChild(j),k.reliableMarginRight=(parseInt((c.defaultView.getComputedStyle(j,null)||{marginRight:0}).marginRight,10)||0)===0),o.innerHTML="",n.removeChild(o);if(a.attachEvent)for(t in{submit:1,change:1,focusin:1})s="on"+t,u=s in a,u||(a.setAttribute(s,"return;"),u=typeof a[s]=="function"),k[t+"Bubbles"]=u;o=l=g=h=m=j=a=i=null;return k}(),f.boxModel=f.support.boxModel;var i=/^(?:\{.*\}|\[.*\])$/,j=/([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!l(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i=f.expando,j=typeof c=="string",k=a.nodeType,l=k?f.cache:a,m=k?a[f.expando]:a[f.expando]&&f.expando;if((!m||e&&m&&l[m]&&!l[m][i])&&j&&d===b)return;m||(k?a[f.expando]=m=++f.uuid:m=f.expando),l[m]||(l[m]={},k||(l[m].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?l[m][i]=f.extend(l[m][i],c):l[m]=f.extend(l[m],c);g=l[m],e&&(g[i]||(g[i]={}),g=g[i]),d!==b&&(g[f.camelCase(c)]=d);if(c==="events"&&!g[c])return g[i]&&g[i].events;j?(h=g[c],h==null&&(h=g[f.camelCase(c)])):h=g;return h}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e=f.expando,g=a.nodeType,h=g?f.cache:a,i=g?a[f.expando]:f.expando;if(!h[i])return;if(b){d=c?h[i][e]:h[i];if(d){d[b]||(b=f.camelCase(b)),delete d[b];if(!l(d))return}}if(c){delete h[i][e];if(!l(h[i]))return}var j=h[i][e];f.support.deleteExpando||!h.setInterval?delete h[i]:h[i]=null,j?(h[i]={},g||(h[i].toJSON=f.noop),h[i][e]=j):g&&(f.support.deleteExpando?delete a[f.expando]:a.removeAttribute?a.removeAttribute(f.expando):a[f.expando]=null)}},_data:function(a,b,c){return f.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=f.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute("classid")===b}return!0}}),f.fn.extend({data:function(a,c){var d=null;if(typeof a=="undefined"){if(this.length){d=f.data(this[0]);if(this[0].nodeType===1){var e=this[0].attributes,g;for(var h=0,i=e.length;h<i;h++)g=e[h].name,g.indexOf("data-")===0&&(g=f.camelCase(g.substring(5)),k(this[0],g,d[g]))}}return d}if(typeof a=="object")return this.each(function(){f.data(this,a)});var j=a.split(".");j[1]=j[1]?"."+j[1]:"";if(c===b){d=this.triggerHandler("getData"+j[1]+"!",[j[0]]),d===b&&this.length&&(d=f.data(this[0],a),d=k(this[0],a,d));return d===b&&j[1]?this.data(j[0]):d}return this.each(function(){var b=f(this),d=[j[0],c];b.triggerHandler("setData"+j[1]+"!",d),f.data(this,a,c),b.triggerHandler("changeData"+j[1]+"!",d)})},removeData:function(a){return this.each(function(){f.removeData(this,a)})}}),f.extend({_mark:function(a,c){a&&(c=(c||"fx")+"mark",f.data(a,c,(f.data(a,c,b,!0)||0)+1,!0))},_unmark:function(a,c,d){a!==!0&&(d=c,c=a,a=!1);if(c){d=d||"fx";var e=d+"mark",g=a?0:(f.data(c,e,b,!0)||1)-1;g?f.data(c,e,g,!0):(f.removeData(c,e,!0),m(c,d,"mark"))}},queue:function(a,c,d){if(a){c=(c||"fx")+"queue";var e=f.data(a,c,b,!0);d&&(!e||f.isArray(d)?e=f.data(a,c,f.makeArray(d),!0):e.push(d));return e||[]}},dequeue:function(a,b){b=b||"fx";var c=f.queue(a,b),d=c.shift(),e;d==="inprogress"&&(d=c.shift()),d&&(b==="fx"&&c.unshift("inprogress"),d.call(a,function(){f.dequeue(a,b)})),c.length||(f.removeData(a,b+"queue",!0),m(a,b,"queue"))}}),f.fn.extend({queue:function(a,c){typeof a!="string"&&(c=a,a="fx");if(c===b)return f.queue(this[0],a);return this.each(function(){var b=f.queue(this,a,c);a==="fx"&&b[0]!=="inprogress"&&f.dequeue(this,a)})},dequeue:function(a){return this.each(function(){f.dequeue(this,a)})},delay:function(a,b){a=f.fx?f.fx.speeds[a]||a:a,b=b||"fx";return this.queue(b,function(){var c=this;setTimeout(function(){f.dequeue(c,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,c){function m(){--h||d.resolveWith(e,[e])}typeof a!="string"&&(c=a,a=b),a=a||"fx";var d=f.Deferred(),e=this,g=e.length,h=1,i=a+"defer",j=a+"queue",k=a+"mark",l;while(g--)if(l=f.data(e[g],i,b,!0)||(f.data(e[g],j,b,!0)||f.data(e[g],k,b,!0))&&f.data(e[g],i,f._Deferred(),!0))h++,l.done(m);m();return d.promise()}});var n=/[\n\t\r]/g,o=/\s+/,p=/\r/g,q=/^(?:button|input)$/i,r=/^(?:button|input|object|select|textarea)$/i,s=/^a(?:rea)?$/i,t=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,u,v;f.fn.extend({attr:function(a,b){return f.access(this,a,b,!0,f.attr)},removeAttr:function(a){return this.each(function(){f.removeAttr(this,a)})},prop:function(a,b){return f.access(this,a,b,!0,f.prop)},removeProp:function(a){a=f.propFix[a]||a;return this.each(function(){try{this[a]=b,delete this[a]}catch(c){}})},addClass:function(a){var b,c,d,e,g,h,i;if(f.isFunction(a))return this.each(function(b){f(this).addClass(a.call(this,b,this.className))});if(a&&typeof a=="string"){b=a.split(o);for(c=0,d=this.length;c<d;c++){e=this[c];if(e.nodeType===1)if(!e.className&&b.length===1)e.className=a;else{g=" "+e.className+" ";for(h=0,i=b.length;h<i;h++)~g.indexOf(" "+b[h]+" ")||(g+=b[h]+" ");e.className=f.trim(g)}}}return this},removeClass:function(a){var c,d,e,g,h,i,j;if(f.isFunction(a))return this.each(function(b){f(this).removeClass(a.call(this,b,this.className))});if(a&&typeof a=="string"||a===b){c=(a||"").split(o);for(d=0,e=this.length;d<e;d++){g=this[d];if(g.nodeType===1&&g.className)if(a){h=(" "+g.className+" ").replace(n," ");for(i=0,j=c.length;i<j;i++)h=h.replace(" "+c[i]+" "," ");g.className=f.trim(h)}else g.className=""}}return this},toggleClass:function(a,b){var c=typeof a,d=typeof b=="boolean";if(f.isFunction(a))return this.each(function(c){f(this).toggleClass(a.call(this,c,this.className,b),b)});return this.each(function(){if(c==="string"){var e,g=0,h=f(this),i=b,j=a.split(o);while(e=j[g++])i=d?i:!h.hasClass(e),h[i?"addClass":"removeClass"](e)}else if(c==="undefined"||c==="boolean")this.className&&f._data(this,"__className__",this.className),this.className=this.className||a===!1?"":f._data(this,"__className__")||""})},hasClass:function(a){var b=" "+a+" ";for(var c=0,d=this.length;c<d;c++)if(this[c].nodeType===1&&(" "+this[c].className+" ").replace(n," ").indexOf(b)>-1)return!0;return!1},val:function(a){var c,d,e=this[0];if(!arguments.length){if(e){c=f.valHooks[e.nodeName.toLowerCase()]||f.valHooks[e.type];if(c&&"get"in c&&(d=c.get(e,"value"))!==b)return d;d=e.value;return typeof d=="string"?d.replace(p,""):d==null?"":d}return b}var g=f.isFunction(a);return this.each(function(d){var e=f(this),h;if(this.nodeType===1){g?h=a.call(this,d,e.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c=a.selectedIndex,d=[],e=a.options,g=a.type==="select-one";if(c<0)return null;for(var h=g?c:0,i=g?c+1:e.length;h<i;h++){var j=e[h];if(j.selected&&(f.support.optDisabled?!j.disabled:j.getAttribute("disabled")===null)&&(!j.parentNode.disabled||!f.nodeName(j.parentNode,"optgroup"))){b=f(j).val();if(g)return b;d.push(b)}}if(g&&!d.length&&e.length)return f(e[c]).val();return d},set:function(a,b){var c=f.makeArray(b);f(a).find("option").each(function(){this.selected=f.inArray(f(this).val(),c)>=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attrFix:{tabindex:"tabIndex"},attr:function(a,c,d,e){var g=a.nodeType;if(!a||g===3||g===8||g===2)return b;if(e&&c in f.attrFn)return f(a)[c](d);if(!("getAttribute"in a))return f.prop(a,c,d);var h,i,j=g!==1||!f.isXMLDoc(a);j&&(c=f.attrFix[c]||c,i=f.attrHooks[c],i||(t.test(c)?i=v:u&&(i=u)));if(d!==b){if(d===null){f.removeAttr(a,c);return b}if(i&&"set"in i&&j&&(h=i.set(a,d,c))!==b)return h;a.setAttribute(c,""+d);return d}if(i&&"get"in i&&j&&(h=i.get(a,c))!==null)return h;h=a.getAttribute(c);return h===null?b:h},removeAttr:function(a,b){var c;a.nodeType===1&&(b=f.attrFix[b]||b,f.attr(a,b,""),a.removeAttribute(b),t.test(b)&&(c=f.propFix[b]||b)in a&&(a[c]=!1))},attrHooks:{type:{set:function(a,b){if(q.test(a.nodeName)&&a.parentNode)f.error("type property can't be changed");else if(!f.support.radioValue&&b==="radio"&&f.nodeName(a,"input")){var c=a.value;a.setAttribute("type",b),c&&(a.value=c);return b}}},value:{get:function(a,b){if(u&&f.nodeName(a,"button"))return u.get(a,b);return b in a?a.value:null},set:function(a,b,c){if(u&&f.nodeName(a,"button"))return u.set(a,b,c);a.value=b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,c,d){var e=a.nodeType;if(!a||e===3||e===8||e===2)return b;var g,h,i=e!==1||!f.isXMLDoc(a);i&&(c=f.propFix[c]||c,h=f.propHooks[c]);return d!==b?h&&"set"in h&&(g=h.set(a,d,c))!==b?g:a[c]=d:h&&"get"in h&&(g=h.get(a,c))!==null?g:a[c]},propHooks:{tabIndex:{get:function(a){var c=a.getAttributeNode("tabindex");return c&&c.specified?parseInt(c.value,10):r.test(a.nodeName)||s.test(a.nodeName)&&a.href?0:b}}}}),f.attrHooks.tabIndex=f.propHooks.tabIndex,v={get:function(a,c){var d;return f.prop(a,c)===!0||(d=a.getAttributeNode(c))&&d.nodeValue!==!1?c.toLowerCase():b},set:function(a,b,c){var d;b===!1?f.removeAttr(a,c):(d=f.propFix[c]||c,d in a&&(a[d]=!0),a.setAttribute(c,c.toLowerCase()));return c}},f.support.getSetAttribute||(u=f.valHooks.button={get:function(a,c){var d;d=a.getAttributeNode(c);return d&&d.nodeValue!==""?d.nodeValue:b},set:function(a,b,d){var e=a.getAttributeNode(d);e||(e=c.createAttribute(d),a.setAttributeNode(e));return e.nodeValue=b+""}},f.each(["width","height"],function(a,b){f.attrHooks[b]=f.extend(f.attrHooks[b],{set:function(a,c){if(c===""){a.setAttribute(b,"auto");return c}}})})),f.support.hrefNormalized||f.each(["href","src","width","height"],function(a,c){f.attrHooks[c]=f.extend(f.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),f.support.style||(f.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=""+b}}),f.support.optSelected||(f.propHooks.selected=f.extend(f.propHooks.selected,{get:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex);return null}})),f.support.checkOn||f.each(["radio","checkbox"],function(){f.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),f.each(["radio","checkbox"],function(){f.valHooks[this]=f.extend(f.valHooks[this],{set:function(a,b){if(f.isArray(b))return a.checked=f.inArray(f(a).val(),b)>=0}})});var w=/\.(.*)$/,x=/^(?:textarea|input|select)$/i,y=/\./g,z=/ /g,A=/[^\w\s.|`]/g,B=function(a){return a.replace(A,"\\$&")};f.event={add:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){if(d===!1)d=C;else if(!d)return;var g,h;d.handler&&(g=d,d=g.handler),d.guid||(d.guid=f.guid++);var i=f._data(a);if(!i)return;var j=i.events,k=i.handle;j||(i.events=j={}),k||(i.handle=k=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.handle.apply(k.elem,arguments):b}),k.elem=a,c=c.split(" ");var l,m=0,n;while(l=c[m++]){h=g?f.extend({},g):{handler:d,data:e},l.indexOf(".")>-1?(n=l.split("."),l=n.shift(),h.namespace=n.slice(0).sort().join(".")):(n=[],h.namespace=""),h.type=l,h.guid||(h.guid=d.guid);var o=j[l],p=f.event.special[l]||{};if(!o){o=j[l]=[];if(!p.setup||p.setup.call(a,e,n,k)===!1)a.addEventListener?a.addEventListener(l,k,!1):a.attachEvent&&a.attachEvent("on"+l,k)}p.add&&(p.add.call(a,h),h.handler.guid||(h.handler.guid=d.guid)),o.push(h),f.event.global[l]=!0}a=null}},global:{},remove:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){d===!1&&(d=C);var g,h,i,j,k=0,l,m,n,o,p,q,r,s=f.hasData(a)&&f._data(a),t=s&&s.events;if(!s||!t)return;c&&c.type&&(d=c.handler,c=c.type);if(!c||typeof c=="string"&&c.charAt(0)==="."){c=c||"";for(h in t)f.event.remove(a,h+c);return}c=c.split(" ");while(h=c[k++]){r=h,q=null,l=h.indexOf(".")<0,m=[],l||(m=h.split("."),h=m.shift(),n=new RegExp("(^|\\.)"+f.map(m.slice(0).sort(),B).join("\\.(?:.*\\.)?")+"(\\.|$)")),p=t[h];if(!p)continue;if(!d){for(j=0;j<p.length;j++){q=p[j];if(l||n.test(q.namespace))f.event.remove(a,r,q.handler,j),p.splice(j--,1)}continue}o=f.event.special[h]||{};for(j=e||0;j<p.length;j++){q=p[j];if(d.guid===q.guid){if(l||n.test(q.namespace))e==null&&p.splice(j--,1),o.remove&&o.remove.call(a,q);if(e!=null)break}}if(p.length===0||e!=null&&p.length===1)(!o.teardown||o.teardown.call(a,m)===!1)&&f.removeEvent(a,h,s.handle),g=null,delete +t[h]}if(f.isEmptyObject(t)){var u=s.handle;u&&(u.elem=null),delete s.events,delete s.handle,f.isEmptyObject(s)&&f.removeData(a,b,!0)}}},customEvent:{getData:!0,setData:!0,changeData:!0},trigger:function(c,d,e,g){var h=c.type||c,i=[],j;h.indexOf("!")>=0&&(h=h.slice(0,-1),j=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if(!!e&&!f.event.customEvent[h]||!!f.event.global[h]){c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.exclusive=j,c.namespace=i.join("."),c.namespace_re=new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)");if(g||!e)c.preventDefault(),c.stopPropagation();if(!e){f.each(f.cache,function(){var a=f.expando,b=this[a];b&&b.events&&b.events[h]&&f.event.trigger(c,d,b.handle.elem)});return}if(e.nodeType===3||e.nodeType===8)return;c.result=b,c.target=e,d=d!=null?f.makeArray(d):[],d.unshift(c);var k=e,l=h.indexOf(":")<0?"on"+h:"";do{var m=f._data(k,"handle");c.currentTarget=k,m&&m.apply(k,d),l&&f.acceptData(k)&&k[l]&&k[l].apply(k,d)===!1&&(c.result=!1,c.preventDefault()),k=k.parentNode||k.ownerDocument||k===c.target.ownerDocument&&a}while(k&&!c.isPropagationStopped());if(!c.isDefaultPrevented()){var n,o=f.event.special[h]||{};if((!o._default||o._default.call(e.ownerDocument,c)===!1)&&(h!=="click"||!f.nodeName(e,"a"))&&f.acceptData(e)){try{l&&e[h]&&(n=e[l],n&&(e[l]=null),f.event.triggered=h,e[h]())}catch(p){}n&&(e[l]=n),f.event.triggered=b}}return c.result}},handle:function(c){c=f.event.fix(c||a.event);var d=((f._data(this,"events")||{})[c.type]||[]).slice(0),e=!c.exclusive&&!c.namespace,g=Array.prototype.slice.call(arguments,0);g[0]=c,c.currentTarget=this;for(var h=0,i=d.length;h<i;h++){var j=d[h];if(e||c.namespace_re.test(j.namespace)){c.handler=j.handler,c.data=j.data,c.handleObj=j;var k=j.handler.apply(this,g);k!==b&&(c.result=k,k===!1&&(c.preventDefault(),c.stopPropagation()));if(c.isImmediatePropagationStopped())break}}return c.result},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),fix:function(a){if(a[f.expando])return a;var d=a;a=f.Event(d);for(var e=this.props.length,g;e;)g=this.props[--e],a[g]=d[g];a.target||(a.target=a.srcElement||c),a.target.nodeType===3&&(a.target=a.target.parentNode),!a.relatedTarget&&a.fromElement&&(a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement);if(a.pageX==null&&a.clientX!=null){var h=a.target.ownerDocument||c,i=h.documentElement,j=h.body;a.pageX=a.clientX+(i&&i.scrollLeft||j&&j.scrollLeft||0)-(i&&i.clientLeft||j&&j.clientLeft||0),a.pageY=a.clientY+(i&&i.scrollTop||j&&j.scrollTop||0)-(i&&i.clientTop||j&&j.clientTop||0)}a.which==null&&(a.charCode!=null||a.keyCode!=null)&&(a.which=a.charCode!=null?a.charCode:a.keyCode),!a.metaKey&&a.ctrlKey&&(a.metaKey=a.ctrlKey),!a.which&&a.button!==b&&(a.which=a.button&1?1:a.button&2?3:a.button&4?2:0);return a},guid:1e8,proxy:f.proxy,special:{ready:{setup:f.bindReady,teardown:f.noop},live:{add:function(a){f.event.add(this,M(a.origType,a.selector),f.extend({},a,{handler:L,guid:a.handler.guid}))},remove:function(a){f.event.remove(this,M(a.origType,a.selector),a)}},beforeunload:{setup:function(a,b,c){f.isWindow(this)&&(this.onbeforeunload=c)},teardown:function(a,b){this.onbeforeunload===b&&(this.onbeforeunload=null)}}}},f.removeEvent=c.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){a.detachEvent&&a.detachEvent("on"+b,c)},f.Event=function(a,b){if(!this.preventDefault)return new f.Event(a,b);a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||a.returnValue===!1||a.getPreventDefault&&a.getPreventDefault()?D:C):this.type=a,b&&f.extend(this,b),this.timeStamp=f.now(),this[f.expando]=!0},f.Event.prototype={preventDefault:function(){this.isDefaultPrevented=D;var a=this.originalEvent;!a||(a.preventDefault?a.preventDefault():a.returnValue=!1)},stopPropagation:function(){this.isPropagationStopped=D;var a=this.originalEvent;!a||(a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=D,this.stopPropagation()},isDefaultPrevented:C,isPropagationStopped:C,isImmediatePropagationStopped:C};var E=function(a){var b=a.relatedTarget,c=!1,d=a.type;a.type=a.data,b!==this&&(b&&(c=f.contains(this,b)),c||(f.event.handle.apply(this,arguments),a.type=d))},F=function(a){a.type=a.data,f.event.handle.apply(this,arguments)};f.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){f.event.special[a]={setup:function(c){f.event.add(this,b,c&&c.selector?F:E,a)},teardown:function(a){f.event.remove(this,b,a&&a.selector?F:E)}}}),f.support.submitBubbles||(f.event.special.submit={setup:function(a,b){if(!f.nodeName(this,"form"))f.event.add(this,"click.specialSubmit",function(a){var b=a.target,c=f.nodeName(b,"input")||f.nodeName(b,"button")?b.type:"";(c==="submit"||c==="image")&&f(b).closest("form").length&&J("submit",this,arguments)}),f.event.add(this,"keypress.specialSubmit",function(a){var b=a.target,c=f.nodeName(b,"input")||f.nodeName(b,"button")?b.type:"";(c==="text"||c==="password")&&f(b).closest("form").length&&a.keyCode===13&&J("submit",this,arguments)});else return!1},teardown:function(a){f.event.remove(this,".specialSubmit")}});if(!f.support.changeBubbles){var G,H=function(a){var b=f.nodeName(a,"input")?a.type:"",c=a.value;b==="radio"||b==="checkbox"?c=a.checked:b==="select-multiple"?c=a.selectedIndex>-1?f.map(a.options,function(a){return a.selected}).join("-"):"":f.nodeName(a,"select")&&(c=a.selectedIndex);return c},I=function(c){var d=c.target,e,g;if(!!x.test(d.nodeName)&&!d.readOnly){e=f._data(d,"_change_data"),g=H(d),(c.type!=="focusout"||d.type!=="radio")&&f._data(d,"_change_data",g);if(e===b||g===e)return;if(e!=null||g)c.type="change",c.liveFired=b,f.event.trigger(c,arguments[1],d)}};f.event.special.change={filters:{focusout:I,beforedeactivate:I,click:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(c==="radio"||c==="checkbox"||f.nodeName(b,"select"))&&I.call(this,a)},keydown:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(a.keyCode===13&&!f.nodeName(b,"textarea")||a.keyCode===32&&(c==="checkbox"||c==="radio")||c==="select-multiple")&&I.call(this,a)},beforeactivate:function(a){var b=a.target;f._data(b,"_change_data",H(b))}},setup:function(a,b){if(this.type==="file")return!1;for(var c in G)f.event.add(this,c+".specialChange",G[c]);return x.test(this.nodeName)},teardown:function(a){f.event.remove(this,".specialChange");return x.test(this.nodeName)}},G=f.event.special.change.filters,G.focus=G.beforeactivate}f.support.focusinBubbles||f.each({focus:"focusin",blur:"focusout"},function(a,b){function e(a){var c=f.event.fix(a);c.type=b,c.originalEvent={},f.event.trigger(c,null,c.target),c.isDefaultPrevented()&&a.preventDefault()}var d=0;f.event.special[b]={setup:function(){d++===0&&c.addEventListener(a,e,!0)},teardown:function(){--d===0&&c.removeEventListener(a,e,!0)}}}),f.each(["bind","one"],function(a,c){f.fn[c]=function(a,d,e){var g;if(typeof a=="object"){for(var h in a)this[c](h,d,a[h],e);return this}if(arguments.length===2||d===!1)e=d,d=b;c==="one"?(g=function(a){f(this).unbind(a,g);return e.apply(this,arguments)},g.guid=e.guid||f.guid++):g=e;if(a==="unload"&&c!=="one")this.one(a,d,e);else for(var i=0,j=this.length;i<j;i++)f.event.add(this[i],a,g,d);return this}}),f.fn.extend({unbind:function(a,b){if(typeof a=="object"&&!a.preventDefault)for(var c in a)this.unbind(c,a[c]);else for(var d=0,e=this.length;d<e;d++)f.event.remove(this[d],a,b);return this},delegate:function(a,b,c,d){return this.live(b,c,d,a)},undelegate:function(a,b,c){return arguments.length===0?this.unbind("live"):this.die(b,null,c,a)},trigger:function(a,b){return this.each(function(){f.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0])return f.event.trigger(a,b,this[0],!0)},toggle:function(a){var b=arguments,c=a.guid||f.guid++,d=0,e=function(c){var e=(f.data(this,"lastToggle"+a.guid)||0)%d;f.data(this,"lastToggle"+a.guid,e+1),c.preventDefault();return b[e].apply(this,arguments)||!1};e.guid=c;while(d<b.length)b[d++].guid=c;return this.click(e)},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var K={focus:"focusin",blur:"focusout",mouseenter:"mouseover",mouseleave:"mouseout"};f.each(["live","die"],function(a,c){f.fn[c]=function(a,d,e,g){var h,i=0,j,k,l,m=g||this.selector,n=g?this:f(this.context);if(typeof a=="object"&&!a.preventDefault){for(var o in a)n[c](o,d,a[o],m);return this}if(c==="die"&&!a&&g&&g.charAt(0)==="."){n.unbind(g);return this}if(d===!1||f.isFunction(d))e=d||C,d=b;a=(a||"").split(" ");while((h=a[i++])!=null){j=w.exec(h),k="",j&&(k=j[0],h=h.replace(w,""));if(h==="hover"){a.push("mouseenter"+k,"mouseleave"+k);continue}l=h,K[h]?(a.push(K[h]+k),h=h+k):h=(K[h]||h)+k;if(c==="live")for(var p=0,q=n.length;p<q;p++)f.event.add(n[p],"live."+M(h,m),{data:d,selector:m,handler:e,origType:h,origHandler:e,preType:l});else n.unbind("live."+M(h,m),e)}return this}}),f.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error".split(" "),function(a,b){f.fn[b]=function(a,c){c==null&&(c=a,a=null);return arguments.length>0?this.bind(b,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0)}),function(){function u(a,b,c,d,e,f){for(var g=0,h=d.length;g<h;g++){var i=d[g];if(i){var j=!1;i=i[a];while(i){if(i.sizcache===c){j=d[i.sizset];break}if(i.nodeType===1){f||(i.sizcache=c,i.sizset=g);if(typeof b!="string"){if(i===b){j=!0;break}}else if(k.filter(b,[i]).length>0){j=i;break}}i=i[a]}d[g]=j}}}function t(a,b,c,d,e,f){for(var g=0,h=d.length;g<h;g++){var i=d[g];if(i){var j=!1;i=i[a];while(i){if(i.sizcache===c){j=d[i.sizset];break}i.nodeType===1&&!f&&(i.sizcache=c,i.sizset=g);if(i.nodeName.toLowerCase()===b){j=i;break}i=i[a]}d[g]=j}}}var a=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d=0,e=Object.prototype.toString,g=!1,h=!0,i=/\\/g,j=/\W/;[0,0].sort(function(){h=!1;return 0});var k=function(b,d,f,g){f=f||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return f;var i,j,n,o,q,r,s,t,u=!0,w=k.isXML(d),x=[],y=b;do{a.exec(""),i=a.exec(y);if(i){y=i[3],x.push(i[1]);if(i[2]){o=i[3];break}}}while(i);if(x.length>1&&m.exec(b))if(x.length===2&&l.relative[x[0]])j=v(x[0]+x[1],d);else{j=l.relative[x[0]]?[d]:k(x.shift(),d);while(x.length)b=x.shift(),l.relative[b]&&(b+=x.shift()),j=v(b,j)}else{!g&&x.length>1&&d.nodeType===9&&!w&&l.match.ID.test(x[0])&&!l.match.ID.test(x[x.length-1])&&(q=k.find(x.shift(),d,w),d=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]);if(d){q=g?{expr:x.pop(),set:p(g)}:k.find(x.pop(),x.length===1&&(x[0]==="~"||x[0]==="+")&&d.parentNode?d.parentNode:d,w),j=q.expr?k.filter(q.expr,q.set):q.set,x.length>0?n=p(j):u=!1;while(x.length)r=x.pop(),s=r,l.relative[r]?s=x.pop():r="",s==null&&(s=d),l.relative[r](n,s,w)}else n=x=[]}n||(n=j),n||k.error(r||b);if(e.call(n)==="[object Array]")if(!u)f.push.apply(f,n);else if(d&&d.nodeType===1)for(t=0;n[t]!=null;t++)n[t]&&(n[t]===!0||n[t].nodeType===1&&k.contains(d,n[t]))&&f.push(j[t]);else for(t=0;n[t]!=null;t++)n[t]&&n[t].nodeType===1&&f.push(j[t]);else p(n,f);o&&(k(o,h,f,g),k.uniqueSort(f));return f};k.uniqueSort=function(a){if(r){g=h,a.sort(r);if(g)for(var b=1;b<a.length;b++)a[b]===a[b-1]&&a.splice(b--,1)}return a},k.matches=function(a,b){return k(a,null,null,b)},k.matchesSelector=function(a,b){return k(b,null,null,[a]).length>0},k.find=function(a,b,c){var d;if(!a)return[];for(var e=0,f=l.order.length;e<f;e++){var g,h=l.order[e];if(g=l.leftMatch[h].exec(a)){var j=g[1];g.splice(1,1);if(j.substr(j.length-1)!=="\\"){g[1]=(g[1]||"").replace(i,""),d=l.find[h](g,b,c);if(d!=null){a=a.replace(l.match[h],"");break}}}}d||(d=typeof b.getElementsByTagName!="undefined"?b.getElementsByTagName("*"):[]);return{set:d,expr:a}},k.filter=function(a,c,d,e){var f,g,h=a,i=[],j=c,m=c&&c[0]&&k.isXML(c[0]);while(a&&c.length){for(var n in l.filter)if((f=l.leftMatch[n].exec(a))!=null&&f[2]){var o,p,q=l.filter[n],r=f[1];g=!1,f.splice(1,1);if(r.substr(r.length-1)==="\\")continue;j===i&&(i=[]);if(l.preFilter[n]){f=l.preFilter[n](f,j,d,i,e,m);if(!f)g=o=!0;else if(f===!0)continue}if(f)for(var s=0;(p=j[s])!=null;s++)if(p){o=q(p,f,s,j);var t=e^!!o;d&&o!=null?t?g=!0:j[s]=!1:t&&(i.push(p),g=!0)}if(o!==b){d||(j=i),a=a.replace(l.match[n],"");if(!g)return[];break}}if(a===h)if(g==null)k.error(a);else break;h=a}return j},k.error=function(a){throw"Syntax error, unrecognized expression: "+a};var l=k.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(a){return a.getAttribute("href")},type:function(a){return a.getAttribute("type")}},relative:{"+":function(a,b){var c=typeof b=="string",d=c&&!j.test(b),e=c&&!d;d&&(b=b.toLowerCase());for(var f=0,g=a.length,h;f<g;f++)if(h=a[f]){while((h=h.previousSibling)&&h.nodeType!==1);a[f]=e||h&&h.nodeName.toLowerCase()===b?h||!1:h===b}e&&k.filter(b,a,!0)},">":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!j.test(b)){b=b.toLowerCase();for(;e<f;e++){c=a[e];if(c){var g=c.parentNode;a[e]=g.nodeName.toLowerCase()===b?g:!1}}}else{for(;e<f;e++)c=a[e],c&&(a[e]=d?c.parentNode:c.parentNode===b);d&&k.filter(b,a,!0)}},"":function(a,b,c){var e,f=d++,g=u;typeof b=="string"&&!j.test(b)&&(b=b.toLowerCase(),e=b,g=t),g("parentNode",b,f,a,e,c)},"~":function(a,b,c){var e,f=d++,g=u;typeof b=="string"&&!j.test(b)&&(b=b.toLowerCase(),e=b,g=t),g("previousSibling",b,f,a,e,c)}},find:{ID:function(a,b,c){if(typeof b.getElementById!="undefined"&&!c){var d=b.getElementById(a[1]);return d&&d.parentNode?[d]:[]}},NAME:function(a,b){if(typeof b.getElementsByName!="undefined"){var c=[],d=b.getElementsByName(a[1]);for(var e=0,f=d.length;e<f;e++)d[e].getAttribute("name")===a[1]&&c.push(d[e]);return c.length===0?null:c}},TAG:function(a,b){if(typeof b.getElementsByTagName!="undefined")return b.getElementsByTagName(a[1])}},preFilter:{CLASS:function(a,b,c,d,e,f){a=" "+a[1].replace(i,"")+" ";if(f)return a;for(var g=0,h;(h=b[g])!=null;g++)h&&(e^(h.className&&(" "+h.className+" ").replace(/[\t\n\r]/g," ").indexOf(a)>=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(i,"")},TAG:function(a,b){return a[1].replace(i,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||k.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&k.error(a[0]);a[0]=d++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(i,"");!f&&l.attrMap[g]&&(a[1]=l.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(i,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=k(b[3],null,null,c);else{var g=k.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(l.match.POS.test(b[0])||l.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!k(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return b<c[3]-0},gt:function(a,b,c){return b>c[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=l.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||k.getText([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h<i;h++)if(g[h]===a)return!1;return!0}k.error(e)},CHILD:function(a,b){var c=b[1],d=a;switch(c){case"only":case"first":while(d=d.previousSibling)if(d.nodeType===1)return!1;if(c==="first")return!0;d=a;case"last":while(d=d.nextSibling)if(d.nodeType===1)return!1;return!0;case"nth":var e=b[2],f=b[3];if(e===1&&f===0)return!0;var g=b[0],h=a.parentNode;if(h&&(h.sizcache!==g||!a.nodeIndex)){var i=0;for(d=h.firstChild;d;d=d.nextSibling)d.nodeType===1&&(d.nodeIndex=++i);h.sizcache=g}var j=a.nodeIndex-f;return e===0?j===0:j%e===0&&j/e>=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=l.attrHandle[c]?l.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=l.setFilters[e];if(f)return f(a,c,b,d)}}},m=l.match.POS,n=function(a,b){return"\\"+(b-0+1)};for(var o in l.match)l.match[o]=new RegExp(l.match[o].source+/(?![^\[]*\])(?![^\(]*\))/.source),l.leftMatch[o]=new RegExp(/(^(?:.|\r|\n)*?)/.source+l.match[o].source.replace(/\\(\d+)/g,n));var p=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(q){p=function(a,b){var c=0,d=b||[];if(e.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var f=a.length;c<f;c++)d.push(a[c]);else for(;a[c];c++)d.push(a[c]);return d}}var r,s;c.documentElement.compareDocumentPosition?r=function(a,b){if(a===b){g=!0;return 0}if(!a.compareDocumentPosition||!b.compareDocumentPosition)return a.compareDocumentPosition?-1:1;return a.compareDocumentPosition(b)&4?-1:1}:(r=function(a,b){if(a===b){g=!0;return 0}if(a.sourceIndex&&b.sourceIndex)return a.sourceIndex-b.sourceIndex;var c,d,e=[],f=[],h=a.parentNode,i=b.parentNode,j=h;if(h===i)return s(a,b);if(!h)return-1;if(!i)return 1;while(j)e.unshift(j),j=j.parentNode;j=i;while(j)f.unshift(j),j=j.parentNode;c=e.length,d=f.length;for(var k=0;k<c&&k<d;k++)if(e[k]!==f[k])return s(e[k],f[k]);return k===c?s(a,f[k],-1):s(e[k],b,1)},s=function(a,b,c){if(a===b)return c;var d=a.nextSibling;while(d){if(d===b)return-1;d=d.nextSibling}return 1}),k.getText=function(a){var b="",c;for(var d=0;a[d];d++)c=a[d],c.nodeType===3||c.nodeType===4?b+=c.nodeValue:c.nodeType!==8&&(b+=k.getText(c.childNodes));return b},function(){var a=c.createElement("div"),d="script"+(new Date).getTime(),e=c.documentElement;a.innerHTML="<a name='"+d+"'/>",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(l.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},l.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(l.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="<a href='#'></a>",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(l.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=k,b=c.createElement("div"),d="__sizzle__";b.innerHTML="<p class='TEST'></p>";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){k=function(b,e,f,g){e=e||c;if(!g&&!k.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return p(e.getElementsByTagName(b),f);if(h[2]&&l.find.CLASS&&e.getElementsByClassName)return p(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return p([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return p([],f);if(i.id===h[3])return p([i],f)}try{return p(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var m=e,n=e.getAttribute("id"),o=n||d,q=e.parentNode,r=/^\s*[+~]/.test(b);n?o=o.replace(/'/g,"\\$&"):e.setAttribute("id",o),r&&q&&(e=e.parentNode);try{if(!r||q)return p(e.querySelectorAll("[id='"+o+"'] "+b),f)}catch(s){}finally{n||m.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)k[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}k.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!k.isXML(a))try{if(e||!l.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return k(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="<div class='test e'></div><div class='test'></div>";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;l.order.splice(1,0,"CLASS"),l.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?k.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?k.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:k.contains=function(){return!1},k.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var v=function(a,b){var c,d=[],e="",f=b.nodeType?[b]:b;while(c=l.match.PSEUDO.exec(a))e+=c[0],a=a.replace(l.match.PSEUDO,"");a=l.relative[a]?a+"*":a;for(var g=0,h=f.length;g<h;g++)k(a,f[g],d);return k.filter(e,d)};f.find=k,f.expr=k.selectors,f.expr[":"]=f.expr.filters,f.unique=k.uniqueSort,f.text=k.getText,f.isXMLDoc=k.isXML,f.contains=k.contains}();var N=/Until$/,O=/^(?:parents|prevUntil|prevAll)/,P=/,/,Q=/^.[^:#\[\.,]*$/,R=Array.prototype.slice,S=f.expr.match.POS,T={children:!0,contents:!0,next:!0,prev:!0};f.fn.extend({find:function(a){var b=this,c,d;if(typeof a!="string")return f(a).filter(function(){for(c=0,d=b.length;c<d;c++)if(f.contains(b[c],this))return!0});var e=this.pushStack("","find",a),g,h,i;for(c=0,d=this.length;c<d;c++){g=e.length,f.find(a,this[c],e);if(c>0)for(h=g;h<e.length;h++)for(i=0;i<g;i++)if(e[i]===e[h]){e.splice(h--,1);break}}return e},has:function(a){var b=f(a);return this.filter(function(){for(var a=0,c=b.length;a<c;a++)if(f.contains(this,b[a]))return!0})},not:function(a){return this.pushStack(V(this,a,!1),"not",a)},filter:function(a){return this.pushStack(V(this,a,!0),"filter",a)},is:function(a){return!!a&&(typeof a=="string"?f.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h,i,j={},k=1;if(g&&a.length){for(d=0,e=a.length;d<e;d++)i=a[d],j[i]||(j[i]=S.test(i)?f(i,b||this.context):i);while(g&&g.ownerDocument&&g!==b){for(i in j)h=j[i],(h.jquery?h.index(g)>-1:f(g).is(h))&&c.push({selector:i,elem:g,level:k});g=g.parentNode,k++}}return c}var l=S.test(a)||typeof a!="string"?f(a,b||this.context):0;for(d=0,e=this.length;d<e;d++){g=this[d];while(g){if(l?l.index(g)>-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a=="string")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(U(c[0])||U(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c),g=R.call(arguments);N.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!T[a]?f.unique(e):e,(this.length>1||P.test(d))&&O.test(a)&&(e=e.reverse());return this.pushStack(e,a,g.join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var W=/ jQuery\d+="(?:\d+|null)"/g,X=/^\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Z=/<([\w:]+)/,$=/<tbody/i,_=/<|&#?\w+;/,ba=/<(?:script|object|embed|option|style)/i,bb=/checked\s*(?:[^=]|=\s*.checked.)/i,bc=/\/(java|ecma)script/i,bd=/^\s*<!(?:\[CDATA\[|\-\-)/,be={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]};be.optgroup=be.option,be.tbody=be.tfoot=be.colgroup=be.caption=be.thead,be.th=be.td,f.support.htmlSerialize||(be._default=[1,"div<div>","</div>"]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){f(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f(arguments[0]).toArray());return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(W,""):null;if(typeof a=="string"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!be[(Z.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Y,"<$1></$2>");try{for(var c=0,d=this.length;c<d;c++)this[c].nodeType===1&&(f.cleanData(this[c].getElementsByTagName("*")),this[c].innerHTML=a)}catch(e){this.empty().append(a)}}else f.isFunction(a)?this.each(function(b){var c=f(this);c.html(a.call(this,b,c.html()))}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&this[0].parentNode){if(f.isFunction(a))return this.each(function(b){var c=f(this),d=c.html();c.replaceWith(a.call(this,b,d))});typeof a!="string"&&(a=f(a).detach());return this.each(function(){var b=this.nextSibling,c=this.parentNode;f(this).remove(),b?f(b).before(a):f(c).append(a)})}return this.length?this.pushStack(f(f.isFunction(a)?a():a),"replaceWith",a):this},detach:function(a){return this.remove(a,!0)},domManip:function(a,c,d){var e,g,h,i,j=a[0],k=[];if(!f.support.checkClone&&arguments.length===3&&typeof j=="string"&&bb.test(j))return this.each(function(){f(this).domManip(a,c,d,!0)});if(f.isFunction(j))return this.each(function(e){var g=f(this);a[0]=j.call(this,e,c?g.html():b),g.domManip(a,c,d)});if(this[0]){i=j&&j.parentNode,f.support.parentNode&&i&&i.nodeType===11&&i.childNodes.length===this.length?e={fragment:i}:e=f.buildFragment(a,this,k),h=e.fragment,h.childNodes.length===1?g=h=h.firstChild:g=h.firstChild;if(g){c=c&&f.nodeName(g,"tr");for(var l=0,m=this.length,n=m-1;l<m;l++)d.call(c?bf(this[l],g):this[l],e.cacheable||m>1&&l<n?f.clone(h,!0,!0):h)}k.length&&f.each(k,bl)}return this}}),f.buildFragment=function(a,b,d){var e,g,h,i;b&&b[0]&&(i=b[0].ownerDocument||b[0]),i.createDocumentFragment||(i=c),a.length===1&&typeof a[0]=="string"&&a[0].length<512&&i===c&&a[0].charAt(0)==="<"&&!ba.test(a[0])&&(f.support.checkClone||!bb.test(a[0]))&&(g=!0,h=f.fragments[a[0]],h&&h!==1&&(e=h)),e||(e=i.createDocumentFragment(),f.clean +(a,i,e,d)),g&&(f.fragments[a[0]]=h?e:1);return{fragment:e,cacheable:g}},f.fragments={},f.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){f.fn[a]=function(c){var d=[],e=f(c),g=this.length===1&&this[0].parentNode;if(g&&g.nodeType===11&&g.childNodes.length===1&&e.length===1){e[b](this[0]);return this}for(var h=0,i=e.length;h<i;h++){var j=(h>0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d=a.cloneNode(!0),e,g,h;if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bh(a,d),e=bi(a),g=bi(d);for(h=0;e[h];++h)g[h]&&bh(e[h],g[h])}if(b){bg(a,d);if(c){e=bi(a),g=bi(d);for(h=0;e[h];++h)bg(e[h],g[h])}}e=g=null;return d},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!_.test(k))k=b.createTextNode(k);else{k=k.replace(Y,"<$1></$2>");var l=(Z.exec(k)||["",""])[1].toLowerCase(),m=be[l]||be._default,n=m[0],o=b.createElement("div");o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=$.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]==="<table>"&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&X.test(k)&&o.insertBefore(b.createTextNode(X.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i<r;i++)bk(k[i]);else bk(k);k.nodeType?h.push(k):h=f.merge(h,k)}if(d){g=function(a){return!a.type||bc.test(a.type)};for(j=0;h[j];j++)if(e&&f.nodeName(h[j],"script")&&(!h[j].type||h[j].type.toLowerCase()==="text/javascript"))e.push(h[j].parentNode?h[j].parentNode.removeChild(h[j]):h[j]);else{if(h[j].nodeType===1){var s=f.grep(h[j].getElementsByTagName("script"),g);h.splice.apply(h,[j+1,0].concat(s))}d.appendChild(h[j])}}return h},cleanData:function(a){var b,c,d=f.cache,e=f.expando,g=f.event.special,h=f.support.deleteExpando;for(var i=0,j;(j=a[i])!=null;i++){if(j.nodeName&&f.noData[j.nodeName.toLowerCase()])continue;c=j[f.expando];if(c){b=d[c]&&d[c][e];if(b&&b.events){for(var k in b.events)g[k]?f.event.remove(j,k):f.removeEvent(j,k,b.handle);b.handle&&(b.handle.elem=null)}h?delete j[f.expando]:j.removeAttribute&&j.removeAttribute(f.expando),delete d[c]}}}});var bm=/alpha\([^)]*\)/i,bn=/opacity=([^)]*)/,bo=/([A-Z]|^ms)/g,bp=/^-?\d+(?:px)?$/i,bq=/^-?\d/,br=/^([\-+])=([\-+.\de]+)/,bs={position:"absolute",visibility:"hidden",display:"block"},bt=["Left","Right"],bu=["Top","Bottom"],bv,bw,bx;f.fn.css=function(a,c){if(arguments.length===2&&c===b)return this;return f.access(this,a,c,!0,function(a,c,d){return d!==b?f.style(a,c,d):f.css(a,c)})},f.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=bv(a,"opacity","opacity");return c===""?"1":c}return a.style.opacity}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":f.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,d,e){if(!!a&&a.nodeType!==3&&a.nodeType!==8&&!!a.style){var g,h,i=f.camelCase(c),j=a.style,k=f.cssHooks[i];c=f.cssProps[i]||i;if(d===b){if(k&&"get"in k&&(g=k.get(a,!1,e))!==b)return g;return j[c]}h=typeof d,h==="string"&&(g=br.exec(d))&&(d=+(g[1]+1)*+g[2]+parseFloat(f.css(a,c)),h="number");if(d==null||h==="number"&&isNaN(d))return;h==="number"&&!f.cssNumber[i]&&(d+="px");if(!k||!("set"in k)||(d=k.set(a,d))!==b)try{j[c]=d}catch(l){}}},css:function(a,c,d){var e,g;c=f.camelCase(c),g=f.cssHooks[c],c=f.cssProps[c]||c,c==="cssFloat"&&(c="float");if(g&&"get"in g&&(e=g.get(a,!0,d))!==b)return e;if(bv)return bv(a,c)},swap:function(a,b,c){var d={};for(var e in b)d[e]=a.style[e],a.style[e]=b[e];c.call(a);for(e in b)a.style[e]=d[e]}}),f.curCSS=f.css,f.each(["height","width"],function(a,b){f.cssHooks[b]={get:function(a,c,d){var e;if(c){if(a.offsetWidth!==0)return by(a,b,d);f.swap(a,bs,function(){e=by(a,b,d)});return e}},set:function(a,b){if(!bp.test(b))return b;b=parseFloat(b);if(b>=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return bn.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNaN(b)?"":"alpha(opacity="+b*100+")",g=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&f.trim(g.replace(bm,""))===""){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bm.test(g)?g.replace(bm,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bv(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(bw=function(a,c){var d,e,g;c=c.replace(bo,"-$1").toLowerCase();if(!(e=a.ownerDocument.defaultView))return b;if(g=e.getComputedStyle(a,null))d=g.getPropertyValue(c),d===""&&!f.contains(a.ownerDocument.documentElement,a)&&(d=f.style(a,c));return d}),c.documentElement.currentStyle&&(bx=function(a,b){var c,d=a.currentStyle&&a.currentStyle[b],e=a.runtimeStyle&&a.runtimeStyle[b],f=a.style;!bp.test(d)&&bq.test(d)&&(c=f.left,e&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b==="fontSize"?"1em":d||0,d=f.pixelLeft+"px",f.left=c,e&&(a.runtimeStyle.left=e));return d===""?"auto":d}),bv=bw||bx,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bz=/%20/g,bA=/\[\]$/,bB=/\r?\n/g,bC=/#.*$/,bD=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bE=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bF=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,bG=/^(?:GET|HEAD)$/,bH=/^\/\//,bI=/\?/,bJ=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,bK=/^(?:select|textarea)/i,bL=/\s+/,bM=/([?&])_=[^&]*/,bN=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bO=f.fn.load,bP={},bQ={},bR,bS,bT=["*/"]+["*"];try{bR=e.href}catch(bU){bR=c.createElement("a"),bR.href="",bR=bR.href}bS=bN.exec(bR.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bO)return bO.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("<div>").append(c.replace(bJ,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bK.test(this.nodeName)||bE.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bB,"\r\n")}}):{name:b.name,value:c.replace(bB,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.bind(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?bX(a,f.ajaxSettings):(b=a,a=f.ajaxSettings),bX(a,b);return a},ajaxSettings:{url:bR,isLocal:bF.test(bS[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":bT},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:bV(bP),ajaxTransport:bV(bQ),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a>0?4:0;var o,r,u,w=c,x=l?bZ(d,v,l):b,y,z;if(a>=200&&a<300||a===304){if(d.ifModified){if(y=v.getResponseHeader("Last-Modified"))f.lastModified[k]=y;if(z=v.getResponseHeader("Etag"))f.etag[k]=z}if(a===304)w="notmodified",o=!0;else try{r=b$(d,x),w="success",o=!0}catch(A){w="parsererror",u=A}}else{u=w;if(!w||a)w="error",a<0&&(a=0)}v.status=a,v.statusText=""+(c||w),o?h.resolveWith(e,[r,w,v]):h.rejectWith(e,[v,w,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.resolveWith(e,[v,w]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f._Deferred(),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bD.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.done,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bC,"").replace(bH,bS[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bL),d.crossDomain==null&&(r=bN.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bS[1]&&r[2]==bS[2]&&(r[3]||(r[1]==="http:"?80:443))==(bS[3]||(bS[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),bW(bP,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bG.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bI.test(d.url)?"&":"?")+d.data,delete d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bM,"$1_="+x);d.url=y+(y===d.url?(bI.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", "+bT+"; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=bW(bQ,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){s<2?w(-1,z):f.error(z)}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)bY(g,a[g],c,e);return d.join("&").replace(bz,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var b_=f.now(),ca=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+b_++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=b.contentType==="application/x-www-form-urlencoded"&&typeof b.data=="string";if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(ca.test(b.url)||e&&ca.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(ca,l),b.url===j&&(e&&(k=k.replace(ca,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var cb=a.ActiveXObject?function(){for(var a in cd)cd[a](0,1)}:!1,cc=0,cd;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ce()||cf()}:ce,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,cb&&delete cd[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cc,cb&&(cd||(cd={},f(a).unload(cb)),cd[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var cg={},ch,ci,cj=/^(?:toggle|show|hide)$/,ck=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,cl,cm=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cn;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cq("show",3),a,b,c);for(var g=0,h=this.length;g<h;g++)d=this[g],d.style&&(e=d.style.display,!f._data(d,"olddisplay")&&e==="none"&&(e=d.style.display=""),e===""&&f.css(d,"display")==="none"&&f._data(d,"olddisplay",cr(d.nodeName)));for(g=0;g<h;g++){d=this[g];if(d.style){e=d.style.display;if(e===""||e==="none")d.style.display=f._data(d,"olddisplay")||""}}return this},hide:function(a,b,c){if(a||a===0)return this.animate(cq("hide",3),a,b,c);for(var d=0,e=this.length;d<e;d++)if(this[d].style){var g=f.css(this[d],"display");g!=="none"&&!f._data(this[d],"olddisplay")&&f._data(this[d],"olddisplay",g)}for(d=0;d<e;d++)this[d].style&&(this[d].style.display="none");return this},_toggle:f.fn.toggle,toggle:function(a,b,c){var d=typeof a=="boolean";f.isFunction(a)&&f.isFunction(b)?this._toggle.apply(this,arguments):a==null||d?this.each(function(){var b=d?a:f(this).is(":hidden");f(this)[b?"show":"hide"]()}):this.animate(cq("toggle",3),a,b,c);return this},fadeTo:function(a,b,c,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=f.speed(b,c,d);if(f.isEmptyObject(a))return this.each(e.complete,[!1]);a=f.extend({},a);return this[e.queue===!1?"each":"queue"](function(){e.queue===!1&&f._mark(this);var b=f.extend({},e),c=this.nodeType===1,d=c&&f(this).is(":hidden"),g,h,i,j,k,l,m,n,o;b.animatedProperties={};for(i in a){g=f.camelCase(i),i!==g&&(a[g]=a[i],delete a[i]),h=a[g],f.isArray(h)?(b.animatedProperties[g]=h[1],h=a[g]=h[0]):b.animatedProperties[g]=b.specialEasing&&b.specialEasing[g]||b.easing||"swing";if(h==="hide"&&d||h==="show"&&!d)return b.complete.call(this);c&&(g==="height"||g==="width")&&(b.overflow=[this.style.overflow,this.style.overflowX,this.style.overflowY],f.css(this,"display")==="inline"&&f.css(this,"float")==="none"&&(f.support.inlineBlockNeedsLayout?(j=cr(this.nodeName),j==="inline"?this.style.display="inline-block":(this.style.display="inline",this.style.zoom=1)):this.style.display="inline-block"))}b.overflow!=null&&(this.style.overflow="hidden");for(i in a)k=new f.fx(this,b,i),h=a[i],cj.test(h)?k[h==="toggle"?d?"show":"hide":h]():(l=ck.exec(h),m=k.cur(),l?(n=parseFloat(l[2]),o=l[3]||(f.cssNumber[i]?"":"px"),o!=="px"&&(f.style(this,i,(n||1)+o),m=(n||1)/k.cur()*m,f.style(this,i,m+o)),l[1]&&(n=(l[1]==="-="?-1:1)*n+m),k.custom(m,n,o)):k.custom(m,h,""));return!0})},stop:function(a,b){a&&this.queue([]),this.each(function(){var a=f.timers,c=a.length;b||f._unmark(!0,this);while(c--)a[c].elem===this&&(b&&a[c](!0),a.splice(c,1))}),b||this.dequeue();return this}}),f.each({slideDown:cq("show",1),slideUp:cq("hide",1),slideToggle:cq("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){f.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),f.extend({speed:function(a,b,c){var d=a&&typeof a=="object"?f.extend({},a):{complete:c||!c&&b||f.isFunction(a)&&a,duration:a,easing:c&&b||b&&!f.isFunction(b)&&b};d.duration=f.fx.off?0:typeof d.duration=="number"?d.duration:d.duration in f.fx.speeds?f.fx.speeds[d.duration]:f.fx.speeds._default,d.old=d.complete,d.complete=function(a){f.isFunction(d.old)&&d.old.call(this),d.queue!==!1?f.dequeue(this):a!==!1&&f._unmark(this)};return d},easing:{linear:function(a,b,c,d){return c+d*a},swing:function(a,b,c,d){return(-Math.cos(a*Math.PI)/2+.5)*d+c}},timers:[],fx:function(a,b,c){this.options=b,this.elem=a,this.prop=c,b.orig=b.orig||{}}}),f.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this),(f.fx.step[this.prop]||f.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];var a,b=f.css(this.elem,this.prop);return isNaN(a=parseFloat(b))?!b||b==="auto"?0:b:a},custom:function(a,b,c){function g(a){return d.step(a)}var d=this,e=f.fx;this.startTime=cn||co(),this.start=a,this.end=b,this.unit=c||this.unit||(f.cssNumber[this.prop]?"":"px"),this.now=this.start,this.pos=this.state=0,g.elem=this.elem,g()&&f.timers.push(g)&&!cl&&(cl=setInterval(e.tick,e.interval))},show:function(){this.options.orig[this.prop]=f.style(this.elem,this.prop),this.options.show=!0,this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur()),f(this.elem).show()},hide:function(){this.options.orig[this.prop]=f.style(this.elem,this.prop),this.options.hide=!0,this.custom(this.cur(),0)},step:function(a){var b=cn||co(),c=!0,d=this.elem,e=this.options,g,h;if(a||b>=e.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),e.animatedProperties[this.prop]=!0;for(g in e.animatedProperties)e.animatedProperties[g]!==!0&&(c=!1);if(c){e.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){d.style["overflow"+b]=e.overflow[a]}),e.hide&&f(d).hide();if(e.hide||e.show)for(var i in e.animatedProperties)f.style(d,i,e.orig[i]);e.complete.call(d)}return!1}e.duration==Infinity?this.now=b:(h=b-this.startTime,this.state=h/e.duration,this.pos=f.easing[e.animatedProperties[this.prop]](this.state,h,0,1,e.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){for(var a=f.timers,b=0;b<a.length;++b)a[b]()||a.splice(b--,1);a.length||f.fx.stop()},interval:13,stop:function(){clearInterval(cl),cl=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){f.style(a.elem,"opacity",a.now)},_default:function(a){a.elem.style&&a.elem.style[a.prop]!=null?a.elem.style[a.prop]=(a.prop==="width"||a.prop==="height"?Math.max(0,a.now):a.now)+a.unit:a.elem[a.prop]=a.now}}}),f.expr&&f.expr.filters&&(f.expr.filters.animated=function(a){return f.grep(f.timers,function(b){return a===b.elem}).length});var cs=/^t(?:able|d|h)$/i,ct=/^(?:body|html)$/i;"getBoundingClientRect"in c.documentElement?f.fn.offset=function(a){var b=this[0],c;if(a)return this.each(function(b){f.offset.setOffset(this,a,b)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return f.offset.bodyOffset(b);try{c=b.getBoundingClientRect()}catch(d){}var e=b.ownerDocument,g=e.documentElement;if(!c||!f.contains(g,b))return c?{top:c.top,left:c.left}:{top:0,left:0};var h=e.body,i=cu(e),j=g.clientTop||h.clientTop||0,k=g.clientLeft||h.clientLeft||0,l=i.pageYOffset||f.support.boxModel&&g.scrollTop||h.scrollTop,m=i.pageXOffset||f.support.boxModel&&g.scrollLeft||h.scrollLeft,n=c.top+l-j,o=c.left+m-k;return{top:n,left:o}}:f.fn.offset=function(a){var b=this[0];if(a)return this.each(function(b){f.offset.setOffset(this,a,b)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return f.offset.bodyOffset(b);f.offset.initialize();var c,d=b.offsetParent,e=b,g=b.ownerDocument,h=g.documentElement,i=g.body,j=g.defaultView,k=j?j.getComputedStyle(b,null):b.currentStyle,l=b.offsetTop,m=b.offsetLeft;while((b=b.parentNode)&&b!==i&&b!==h){if(f.offset.supportsFixedPosition&&k.position==="fixed")break;c=j?j.getComputedStyle(b,null):b.currentStyle,l-=b.scrollTop,m-=b.scrollLeft,b===d&&(l+=b.offsetTop,m+=b.offsetLeft,f.offset.doesNotAddBorder&&(!f.offset.doesAddBorderForTableAndCells||!cs.test(b.nodeName))&&(l+=parseFloat(c.borderTopWidth)||0,m+=parseFloat(c.borderLeftWidth)||0),e=d,d=b.offsetParent),f.offset.subtractsBorderForOverflowNotVisible&&c.overflow!=="visible"&&(l+=parseFloat(c.borderTopWidth)||0,m+=parseFloat(c.borderLeftWidth)||0),k=c}if(k.position==="relative"||k.position==="static")l+=i.offsetTop,m+=i.offsetLeft;f.offset.supportsFixedPosition&&k.position==="fixed"&&(l+=Math.max(h.scrollTop,i.scrollTop),m+=Math.max(h.scrollLeft,i.scrollLeft));return{top:l,left:m}},f.offset={initialize:function(){var a=c.body,b=c.createElement("div"),d,e,g,h,i=parseFloat(f.css(a,"marginTop"))||0,j="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";f.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"}),b.innerHTML=j,a.insertBefore(b,a.firstChild),d=b.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,this.doesNotAddBorder=e.offsetTop!==5,this.doesAddBorderForTableAndCells=h.offsetTop===5,e.style.position="fixed",e.style.top="20px",this.supportsFixedPosition=e.offsetTop===20||e.offsetTop===15,e.style.position=e.style.top="",d.style.overflow="hidden",d.style.position="relative",this.subtractsBorderForOverflowNotVisible=e.offsetTop===-5,this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==i,a.removeChild(b),f.offset.initialize=f.noop},bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;f.offset.initialize(),f.offset.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(f.css(a,"marginTop"))||0,c+=parseFloat(f.css(a,"marginLeft"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var d=f.css(a,"position");d==="static"&&(a.style.position="relative");var e=f(a),g=e.offset(),h=f.css(a,"top"),i=f.css(a,"left"),j=(d==="absolute"||d==="fixed")&&f.inArray("auto",[h,i])>-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=ct.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!ct.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each(["Left","Top"],function(a,c){var d="scroll"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cu(e);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cu(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each(["Height","Width"],function(a,c){var d=c.toLowerCase();f.fn["inner"+c]=function(){var a=this[0];return a&&a.style?parseFloat(f.css(a,d,"padding")):null},f.fn["outer"+c]=function(a){var b=this[0];return b&&b.style?parseFloat(f.css(b,d,a?"margin":"border")):null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement["client"+c],h=e.document.body;return e.document.compatMode==="CSS1Compat"&&g||h&&h["client"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement["client"+c],e.body["scroll"+c],e.documentElement["scroll"+c],e.body["offset"+c],e.documentElement["offset"+c]);if(a===b){var i=f.css(e,d),j=parseFloat(i);return f.isNaN(j)?i:j}return this.css(d,typeof a=="string"?a:a+"px")}}),a.jQuery=a.$=f})(window);
\ No newline at end of file diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/js/search.js b/jni/ruby/lib/rdoc/generator/template/darkfish/js/search.js new file mode 100644 index 0000000..60ac295 --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/js/search.js @@ -0,0 +1,109 @@ +Search = function(data, input, result) { + this.data = data; + this.$input = $(input); + this.$result = $(result); + + this.$current = null; + this.$view = this.$result.parent(); + this.searcher = new Searcher(data.index); + this.init(); +} + +Search.prototype = $.extend({}, Navigation, new function() { + var suid = 1; + + this.init = function() { + var _this = this; + var observer = function(e) { + switch(e.originalEvent.keyCode) { + case 38: // Event.KEY_UP + case 40: // Event.KEY_DOWN + return; + } + _this.search(_this.$input[0].value); + }; + this.$input.keyup(observer); + this.$input.click(observer); // mac's clear field + + this.searcher.ready(function(results, isLast) { + _this.addResults(results, isLast); + }) + + this.initNavigation(); + this.setNavigationActive(false); + } + + this.search = function(value, selectFirstMatch) { + value = jQuery.trim(value).toLowerCase(); + if (value) { + this.setNavigationActive(true); + } else { + this.setNavigationActive(false); + } + + if (value == '') { + this.lastQuery = value; + this.$result.empty(); + this.$result.attr('aria-expanded', 'false'); + this.setNavigationActive(false); + } else if (value != this.lastQuery) { + this.lastQuery = value; + this.$result.attr('aria-busy', 'true'); + this.$result.attr('aria-expanded', 'true'); + this.firstRun = true; + this.searcher.find(value); + } + } + + this.addResults = function(results, isLast) { + var target = this.$result.get(0); + if (this.firstRun && (results.length > 0 || isLast)) { + this.$current = null; + this.$result.empty(); + } + + for (var i=0, l = results.length; i < l; i++) { + var item = this.renderItem.call(this, results[i]); + item.setAttribute('id', 'search-result-' + target.childElementCount); + target.appendChild(item); + }; + + if (this.firstRun && results.length > 0) { + this.firstRun = false; + this.$current = $(target.firstChild); + this.$current.addClass('search-selected'); + } + if (jQuery.browser.msie) this.$element[0].className += ''; + + if (isLast) this.$result.attr('aria-busy', 'false'); + } + + this.move = function(isDown) { + if (!this.$current) return; + var $next = this.$current[isDown ? 'next' : 'prev'](); + if ($next.length) { + this.$current.removeClass('search-selected'); + $next.addClass('search-selected'); + this.$input.attr('aria-activedescendant', $next.attr('id')); + this.scrollIntoView($next[0], this.$view[0]); + this.$current = $next; + this.$input.val($next[0].firstChild.firstChild.text); + this.$input.select(); + } + return true; + } + + this.hlt = function(html) { + return this.escapeHTML(html). + replace(/\u0001/g, '<em>'). + replace(/\u0002/g, '</em>'); + } + + this.escapeHTML = function(html) { + return html.replace(/[&<>]/g, function(c) { + return '&#' + c.charCodeAt(0) + ';'; + }); + } + +}); + diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/page.rhtml b/jni/ruby/lib/rdoc/generator/template/darkfish/page.rhtml new file mode 100644 index 0000000..4a6b006 --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/page.rhtml @@ -0,0 +1,18 @@ +<body id="top" role="document" class="file"> +<nav role="navigation"> + <div id="project-navigation"> + <%= render '_sidebar_navigation.rhtml' %> + <%= render '_sidebar_search.rhtml' %> + </div> + + <%= render '_sidebar_table_of_contents.rhtml' %> + + <div id="project-metadata"> + <%= render '_sidebar_pages.rhtml' %> + </div> +</nav> + +<main role="main" aria-label="Page <%=h file.full_name%>"> +<%= file.description %> +</main> + diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/servlet_not_found.rhtml b/jni/ruby/lib/rdoc/generator/template/darkfish/servlet_not_found.rhtml new file mode 100644 index 0000000..f084157 --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/servlet_not_found.rhtml @@ -0,0 +1,18 @@ +<body role="document"> +<nav role="navigation"> + <%= render '_sidebar_navigation.rhtml' %> + + <%= render '_sidebar_search.rhtml' %> + + <div id="project-metadata"> + <%= render '_sidebar_pages.rhtml' %> + <%= render '_sidebar_classes.rhtml' %> + </div> +</nav> + +<main role="main"> + <h1>Not Found</h1> + + <p><%= message %> +</main> + diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/servlet_root.rhtml b/jni/ruby/lib/rdoc/generator/template/darkfish/servlet_root.rhtml new file mode 100644 index 0000000..3a33659 --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/servlet_root.rhtml @@ -0,0 +1,63 @@ +<body role="document"> +<nav role="navigation"> + <div id="project-navigation"> + <div id="home-section" class="nav-section"> + <h2> + <a href="<%= rel_prefix %>/" rel="home">Home</a> + </h2> + </div> + + <%= render '_sidebar_search.rhtml' %> + </div> + +<%= render '_sidebar_installed.rhtml' %> +</nav> + +<main role="main"> + <h1>Local RDoc Documentation</h1> + + <p>Here you can browse local documentation from the ruby standard library and + your installed gems. + +<% extra_dirs = installed.select { |_, _, _, type,| type == :extra } %> +<% unless extra_dirs.empty? %> + <h2>Extra Documentation Directories</h2> + + <p>The following additional documentation directories are available:</p> + + <ol> + <% extra_dirs.each do |name, href, exists, _, path| %> + <li> + <% if exists %> + <a href="<%= href %>"><%= h name %></a> (<%= h path %>) + <% else %> + <%= h name %> (<%= h path %>; <i>not available</i>) + <% end %> + </li> + <% end %> + </ol> +<% end %> + +<% gems = installed.select { |_, _, _, type,| type == :gem } %> +<% missing = gems.reject { |_, _, exists,| exists } %> +<% unless missing.empty? then %> + <h2>Missing Gem Documentation</h2> + + <p>You are missing documentation for some of your installed gems. + You can install missing documentation for gems by running + <kbd>gem rdoc --all</kbd>. After installing the missing documentation you + only need to reload this page. The newly created documentation will + automatically appear. + + <p>You can also install documentation for a specific gem by running one of + the following commands. + + <ul> + <% names = missing.map { |name,| name.sub(/-([^-]*)$/, '') }.uniq %> + <% names.each do |name| %> + <li><kbd>gem rdoc <%=h name %></kbd> + <% end %> + </ul> +<% end %> +</main> + diff --git a/jni/ruby/lib/rdoc/generator/template/darkfish/table_of_contents.rhtml b/jni/ruby/lib/rdoc/generator/template/darkfish/table_of_contents.rhtml new file mode 100644 index 0000000..7ff1a9e --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/darkfish/table_of_contents.rhtml @@ -0,0 +1,58 @@ +<body id="top" class="table-of-contents"> +<main role="main"> +<h1 class="class"><%= h @title %></h1> + +<% simple_files = @files.select { |f| f.text? } %> +<% unless simple_files.empty? then %> +<h2 id="pages">Pages</h2> +<ul> +<% simple_files.sort.each do |file| %> + <li class="file"> + <a href="<%= file.path %>"><%= h file.page_name %></a> +<% + # HACK table_of_contents should not exist on Document + table = file.parse(file.comment).table_of_contents + unless table.empty? then %> + <ul> +<% table.each do |heading| %> + <li><a href="<%= file.path %>#<%= heading.aref %>"><%= heading.plain_html %></a> +<% end %> + </ul> +<% end %> + </li> + <% end %> +</ul> +<% end %> + +<h2 id="classes">Classes and Modules</h2> +<ul> +<% @modsort.each do |klass| %> + <li class="<%= klass.type %>"> + <a href="<%= klass.path %>"><%= klass.full_name %></a> +<% table = [] + table.concat klass.parse(klass.comment_location).table_of_contents + table.concat klass.section_contents + + unless table.empty? then %> + <ul> +<% table.each do |item| %> + <li><a href="<%= klass.path %>#<%= item.aref %>"><%= item.plain_html %></a> +<% end %> + </ul> +<% end %> + </li> +<% end %> +</ul> + +<h2 id="methods">Methods</h2> +<ul> +<% @store.all_classes_and_modules.map do |mod| + mod.method_list + end.flatten.sort.each do |method| %> + <li class="method"> + <a href="<%= method.path %>"><%= h method.pretty_name %></a> + — + <span class="container"><%= method.parent.full_name %></span> +<% end %> +</ul> +</main> diff --git a/jni/ruby/lib/rdoc/generator/template/json_index/.document b/jni/ruby/lib/rdoc/generator/template/json_index/.document new file mode 100644 index 0000000..1713b67 --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/json_index/.document @@ -0,0 +1 @@ +# ignore all files in this directory diff --git a/jni/ruby/lib/rdoc/generator/template/json_index/js/navigation.js b/jni/ruby/lib/rdoc/generator/template/json_index/js/navigation.js new file mode 100644 index 0000000..e412681 --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/json_index/js/navigation.js @@ -0,0 +1,142 @@ +/* + * Navigation allows movement using the arrow keys through the search results. + * + * When using this library you will need to set scrollIntoView to the + * appropriate function for your layout. Use scrollInWindow if the container + * is not scrollable and scrollInElement if the container is a separate + * scrolling region. + */ +Navigation = new function() { + this.initNavigation = function() { + var _this = this; + + $(document).keydown(function(e) { + _this.onkeydown(e); + }).keyup(function(e) { + _this.onkeyup(e); + }); + + this.navigationActive = true; + } + + this.setNavigationActive = function(state) { + this.navigationActive = state; + this.clearMoveTimeout(); + } + + this.onkeyup = function(e) { + if (!this.navigationActive) return; + + switch(e.keyCode) { + case 37: //Event.KEY_LEFT: + case 38: //Event.KEY_UP: + case 39: //Event.KEY_RIGHT: + case 40: //Event.KEY_DOWN: + this.clearMoveTimeout(); + break; + } + } + + this.onkeydown = function(e) { + if (!this.navigationActive) return; + switch(e.keyCode) { + case 37: //Event.KEY_LEFT: + if (this.moveLeft()) e.preventDefault(); + break; + case 38: //Event.KEY_UP: + if (e.keyCode == 38 || e.ctrlKey) { + if (this.moveUp()) e.preventDefault(); + this.startMoveTimeout(false); + } + break; + case 39: //Event.KEY_RIGHT: + if (this.moveRight()) e.preventDefault(); + break; + case 40: //Event.KEY_DOWN: + if (e.keyCode == 40 || e.ctrlKey) { + if (this.moveDown()) e.preventDefault(); + this.startMoveTimeout(true); + } + break; + case 13: //Event.KEY_RETURN: + if (this.$current) + e.preventDefault(); + this.select(this.$current); + break; + } + if (e.ctrlKey && e.shiftKey) this.select(this.$current); + } + + this.clearMoveTimeout = function() { + clearTimeout(this.moveTimeout); + this.moveTimeout = null; + } + + this.startMoveTimeout = function(isDown) { + if (!$.browser.mozilla && !$.browser.opera) return; + if (this.moveTimeout) this.clearMoveTimeout(); + var _this = this; + + var go = function() { + if (!_this.moveTimeout) return; + _this[isDown ? 'moveDown' : 'moveUp'](); + _this.moveTimout = setTimeout(go, 100); + } + this.moveTimeout = setTimeout(go, 200); + } + + this.moveRight = function() { + } + + this.moveLeft = function() { + } + + this.move = function(isDown) { + } + + this.moveUp = function() { + return this.move(false); + } + + this.moveDown = function() { + return this.move(true); + } + + /* + * Scrolls to the given element in the scrollable element view. + */ + this.scrollInElement = function(element, view) { + var offset, viewHeight, viewScroll, height; + offset = element.offsetTop; + height = element.offsetHeight; + viewHeight = view.offsetHeight; + viewScroll = view.scrollTop; + + if (offset - viewScroll + height > viewHeight) { + view.scrollTop = offset - viewHeight + height; + } + if (offset < viewScroll) { + view.scrollTop = offset; + } + } + + /* + * Scrolls to the given element in the window. The second argument is + * ignored + */ + this.scrollInWindow = function(element, ignored) { + var offset, viewHeight, viewScroll, height; + offset = element.offsetTop; + height = element.offsetHeight; + viewHeight = window.innerHeight; + viewScroll = window.scrollY; + + if (offset - viewScroll + height > viewHeight) { + window.scrollTo(window.scrollX, offset - viewHeight + height); + } + if (offset < viewScroll) { + window.scrollTo(window.scrollX, offset); + } + } +} + diff --git a/jni/ruby/lib/rdoc/generator/template/json_index/js/searcher.js b/jni/ruby/lib/rdoc/generator/template/json_index/js/searcher.js new file mode 100644 index 0000000..f854b54 --- /dev/null +++ b/jni/ruby/lib/rdoc/generator/template/json_index/js/searcher.js @@ -0,0 +1,228 @@ +Searcher = function(data) { + this.data = data; + this.handlers = []; +} + +Searcher.prototype = new function() { + // search is performed in chunks of 1000 for non-blocking user input + var CHUNK_SIZE = 1000; + // do not try to find more than 100 results + var MAX_RESULTS = 100; + var huid = 1; + var suid = 1; + var runs = 0; + + this.find = function(query) { + var queries = splitQuery(query); + var regexps = buildRegexps(queries); + var highlighters = buildHilighters(queries); + var state = { from: 0, pass: 0, limit: MAX_RESULTS, n: suid++}; + var _this = this; + + this.currentSuid = state.n; + + if (!query) return; + + var run = function() { + // stop current search thread if new search started + if (state.n != _this.currentSuid) return; + + var results = + performSearch(_this.data, regexps, queries, highlighters, state); + var hasMore = (state.limit > 0 && state.pass < 4); + + triggerResults.call(_this, results, !hasMore); + if (hasMore) { + setTimeout(run, 2); + } + runs++; + }; + runs = 0; + + // start search thread + run(); + } + + /* ----- Events ------ */ + this.ready = function(fn) { + fn.huid = huid; + this.handlers.push(fn); + } + + /* ----- Utilities ------ */ + function splitQuery(query) { + return jQuery.grep(query.split(/(\s+|::?|\(\)?)/), function(string) { + return string.match(/\S/) + }); + } + + function buildRegexps(queries) { + return jQuery.map(queries, function(query) { + return new RegExp(query.replace(/(.)/g, '([$1])([^$1]*?)'), 'i') + }); + } + + function buildHilighters(queries) { + return jQuery.map(queries, function(query) { + return jQuery.map(query.split(''), function(l, i) { + return '\u0001$' + (i*2+1) + '\u0002$' + (i*2+2); + }).join(''); + }); + } + + // function longMatchRegexp(index, longIndex, regexps) { + // for (var i = regexps.length - 1; i >= 0; i--){ + // if (!index.match(regexps[i]) && !longIndex.match(regexps[i])) return false; + // }; + // return true; + // } + + + /* ----- Mathchers ------ */ + + /* + * This record matches if the index starts with queries[0] and the record + * matches all of the regexps + */ + function matchPassBeginning(index, longIndex, queries, regexps) { + if (index.indexOf(queries[0]) != 0) return false; + for (var i=1, l = regexps.length; i < l; i++) { + if (!index.match(regexps[i]) && !longIndex.match(regexps[i])) + return false; + }; + return true; + } + + /* + * This record matches if the longIndex starts with queries[0] and the + * longIndex matches all of the regexps + */ + function matchPassLongIndex(index, longIndex, queries, regexps) { + if (longIndex.indexOf(queries[0]) != 0) return false; + for (var i=1, l = regexps.length; i < l; i++) { + if (!longIndex.match(regexps[i])) + return false; + }; + return true; + } + + /* + * This record matches if the index contains queries[0] and the record + * matches all of the regexps + */ + function matchPassContains(index, longIndex, queries, regexps) { + if (index.indexOf(queries[0]) == -1) return false; + for (var i=1, l = regexps.length; i < l; i++) { + if (!index.match(regexps[i]) && !longIndex.match(regexps[i])) + return false; + }; + return true; + } + + /* + * This record matches if regexps[0] matches the index and the record + * matches all of the regexps + */ + function matchPassRegexp(index, longIndex, queries, regexps) { + if (!index.match(regexps[0])) return false; + for (var i=1, l = regexps.length; i < l; i++) { + if (!index.match(regexps[i]) && !longIndex.match(regexps[i])) + return false; + }; + return true; + } + + + /* ----- Highlighters ------ */ + function highlightRegexp(info, queries, regexps, highlighters) { + var result = createResult(info); + for (var i=0, l = regexps.length; i < l; i++) { + result.title = result.title.replace(regexps[i], highlighters[i]); + result.namespace = result.namespace.replace(regexps[i], highlighters[i]); + }; + return result; + } + + function hltSubstring(string, pos, length) { + return string.substring(0, pos) + '\u0001' + string.substring(pos, pos + length) + '\u0002' + string.substring(pos + length); + } + + function highlightQuery(info, queries, regexps, highlighters) { + var result = createResult(info); + var pos = 0; + var lcTitle = result.title.toLowerCase(); + + pos = lcTitle.indexOf(queries[0]); + if (pos != -1) { + result.title = hltSubstring(result.title, pos, queries[0].length); + } + + result.namespace = result.namespace.replace(regexps[0], highlighters[0]); + for (var i=1, l = regexps.length; i < l; i++) { + result.title = result.title.replace(regexps[i], highlighters[i]); + result.namespace = result.namespace.replace(regexps[i], highlighters[i]); + }; + return result; + } + + function createResult(info) { + var result = {}; + result.title = info[0]; + result.namespace = info[1]; + result.path = info[2]; + result.params = info[3]; + result.snippet = info[4]; + return result; + } + + /* ----- Searching ------ */ + function performSearch(data, regexps, queries, highlighters, state) { + var searchIndex = data.searchIndex; + var longSearchIndex = data.longSearchIndex; + var info = data.info; + var result = []; + var i = state.from; + var l = searchIndex.length; + var togo = CHUNK_SIZE; + var matchFunc, hltFunc; + + while (state.pass < 4 && state.limit > 0 && togo > 0) { + if (state.pass == 0) { + matchFunc = matchPassBeginning; + hltFunc = highlightQuery; + } else if (state.pass == 1) { + matchFunc = matchPassLongIndex; + hltFunc = highlightQuery; + } else if (state.pass == 2) { + matchFunc = matchPassContains; + hltFunc = highlightQuery; + } else if (state.pass == 3) { + matchFunc = matchPassRegexp; + hltFunc = highlightRegexp; + } + + for (; togo > 0 && i < l && state.limit > 0; i++, togo--) { + if (info[i].n == state.n) continue; + if (matchFunc(searchIndex[i], longSearchIndex[i], queries, regexps)) { + info[i].n = state.n; + result.push(hltFunc(info[i], queries, regexps, highlighters)); + state.limit--; + } + }; + if (searchIndex.length <= i) { + state.pass++; + i = state.from = 0; + } else { + state.from = i; + } + } + return result; + } + + function triggerResults(results, isLast) { + jQuery.each(this.handlers, function(i, fn) { + fn.call(this, results, isLast) + }) + } +} + diff --git a/jni/ruby/lib/rdoc/ghost_method.rb b/jni/ruby/lib/rdoc/ghost_method.rb new file mode 100644 index 0000000..7eb2d93 --- /dev/null +++ b/jni/ruby/lib/rdoc/ghost_method.rb @@ -0,0 +1,6 @@ +## +# GhostMethod represents a method referenced only by a comment + +class RDoc::GhostMethod < RDoc::AnyMethod +end + diff --git a/jni/ruby/lib/rdoc/i18n.rb b/jni/ruby/lib/rdoc/i18n.rb new file mode 100644 index 0000000..4cccbc6 --- /dev/null +++ b/jni/ruby/lib/rdoc/i18n.rb @@ -0,0 +1,9 @@ +## +# This module provides i18n realated features. + +module RDoc::I18n + + autoload :Locale, 'rdoc/i18n/locale' + autoload :Text, 'rdoc/i18n/text' + +end diff --git a/jni/ruby/lib/rdoc/i18n/locale.rb b/jni/ruby/lib/rdoc/i18n/locale.rb new file mode 100644 index 0000000..e98732e --- /dev/null +++ b/jni/ruby/lib/rdoc/i18n/locale.rb @@ -0,0 +1,101 @@ +## +# A message container for a locale. +# +# This object provides the following two features: +# +# * Loads translated messages from .po file. +# * Translates a message into the locale. + +class RDoc::I18n::Locale + + @@locales = {} # :nodoc: + + class << self + + ## + # Returns the locale object for +locale_name+. + + def [](locale_name) + @@locales[locale_name] ||= new(locale_name) + end + + ## + # Sets the locale object for +locale_name+. + # + # Normally, this method is not used. This method is useful for + # testing. + + def []=(locale_name, locale) + @@locales[locale_name] = locale + end + + end + + ## + # The name of the locale. It uses IETF language tag format + # +[language[_territory][.codeset][@modifier]]+. + # + # See also {BCP 47 - Tags for Identifying + # Languages}[http://tools.ietf.org/rfc/bcp/bcp47.txt]. + + attr_reader :name + + ## + # Creates a new locale object for +name+ locale. +name+ must + # follow IETF language tag format. + + def initialize(name) + @name = name + @messages = {} + end + + ## + # Loads translation messages from +locale_directory+/+@name+/rdoc.po + # or +locale_directory+/+@name+.po. The former has high priority. + # + # This method requires gettext gem for parsing .po file. If you + # don't have gettext gem, this method doesn't load .po file. This + # method warns and returns +false+. + # + # Returns +true+ if succeeded, +false+ otherwise. + + def load(locale_directory) + return false if @name.nil? + + po_file_candidates = [ + File.join(locale_directory, @name, 'rdoc.po'), + File.join(locale_directory, "#{@name}.po"), + ] + po_file = po_file_candidates.find do |po_file_candidate| + File.exist?(po_file_candidate) + end + return false unless po_file + + begin + require 'gettext/po_parser' + require 'gettext/mo' + rescue LoadError + warn('Need gettext gem for i18n feature:') + warn(' gem install gettext') + return false + end + + po_parser = GetText::POParser.new + messages = GetText::MO.new + po_parser.report_warning = false + po_parser.parse_file(po_file, messages) + + @messages.merge!(messages) + + true + end + + ## + # Translates the +message+ into locale. If there is no tranlsation + # messages for +message+ in locale, +message+ itself is returned. + + def translate(message) + @messages[message] || message + end + +end diff --git a/jni/ruby/lib/rdoc/i18n/text.rb b/jni/ruby/lib/rdoc/i18n/text.rb new file mode 100644 index 0000000..ee5c66a --- /dev/null +++ b/jni/ruby/lib/rdoc/i18n/text.rb @@ -0,0 +1,125 @@ +## +# An i18n supported text. +# +# This object provides the following two features: +# +# * Extracts translation messages from wrapped raw text. +# * Translates wrapped raw text in specified locale. +# +# Wrapped raw text is one of String, RDoc::Comment or Array of them. + +class RDoc::I18n::Text + + ## + # Creates a new i18n supported text for +raw+ text. + + def initialize(raw) + @raw = raw + end + + ## + # Extracts translation target messages and yields each message. + # + # Each yielded message is a Hash. It consists of the followings: + # + # :type :: :paragraph + # :paragraph :: String (The translation target message itself.) + # :line_no :: Integer (The line number of the :paragraph is started.) + # + # The above content may be added in the future. + + def extract_messages + parse do |part| + case part[:type] + when :empty_line + # ignore + when :paragraph + yield(part) + end + end + end + + # Translates raw text into +locale+. + def translate(locale) + translated_text = '' + parse do |part| + case part[:type] + when :paragraph + translated_text << locale.translate(part[:paragraph]) + when :empty_line + translated_text << part[:line] + else + raise "should not reach here: unexpected type: #{type}" + end + end + translated_text + end + + private + def parse(&block) + paragraph = '' + paragraph_start_line = 0 + line_no = 0 + + each_line(@raw) do |line| + line_no += 1 + case line + when /\A\s*\z/ + if paragraph.empty? + emit_empty_line_event(line, line_no, &block) + else + paragraph << line + emit_paragraph_event(paragraph, paragraph_start_line, line_no, + &block) + paragraph = '' + end + else + paragraph_start_line = line_no if paragraph.empty? + paragraph << line + end + end + + unless paragraph.empty? + emit_paragraph_event(paragraph, paragraph_start_line, line_no, &block) + end + end + + def each_line(raw, &block) + case raw + when RDoc::Comment + raw.text.each_line(&block) + when Array + raw.each do |comment, location| + each_line(comment, &block) + end + else + raw.each_line(&block) + end + end + + def emit_empty_line_event(line, line_no) + part = { + :type => :empty_line, + :line => line, + :line_no => line_no, + } + yield(part) + end + + def emit_paragraph_event(paragraph, paragraph_start_line, line_no, &block) + paragraph_part = { + :type => :paragraph, + :line_no => paragraph_start_line, + } + match_data = /(\s*)\z/.match(paragraph) + if match_data + paragraph_part[:paragraph] = match_data.pre_match + yield(paragraph_part) + emit_empty_line_event(match_data[1], line_no, &block) + else + paragraph_part[:paragraph] = paragraph + yield(paragraph_part) + end + end + +end diff --git a/jni/ruby/lib/rdoc/include.rb b/jni/ruby/lib/rdoc/include.rb new file mode 100644 index 0000000..75ed9c7 --- /dev/null +++ b/jni/ruby/lib/rdoc/include.rb @@ -0,0 +1,9 @@ +## +# A Module included in a class with \#include +# +# RDoc::Include.new 'Enumerable', 'comment ...' + +class RDoc::Include < RDoc::Mixin + +end + diff --git a/jni/ruby/lib/rdoc/known_classes.rb b/jni/ruby/lib/rdoc/known_classes.rb new file mode 100644 index 0000000..a04068a --- /dev/null +++ b/jni/ruby/lib/rdoc/known_classes.rb @@ -0,0 +1,72 @@ +module RDoc + + ## + # Ruby's built-in classes, modules and exceptions + + KNOWN_CLASSES = { + "rb_cArray" => "Array", + "rb_cBasicObject" => "BasicObject", + "rb_cBignum" => "Bignum", + "rb_cClass" => "Class", + "rb_cData" => "Data", + "rb_cDir" => "Dir", + "rb_cEncoding" => "Encoding", + "rb_cFalseClass" => "FalseClass", + "rb_cFile" => "File", + "rb_cFixnum" => "Fixnum", + "rb_cFloat" => "Float", + "rb_cHash" => "Hash", + "rb_cIO" => "IO", + "rb_cInteger" => "Integer", + "rb_cModule" => "Module", + "rb_cNilClass" => "NilClass", + "rb_cNumeric" => "Numeric", + "rb_cObject" => "Object", + "rb_cProc" => "Proc", + "rb_cRange" => "Range", + "rb_cRegexp" => "Regexp", + "rb_cRubyVM" => "RubyVM", + "rb_cSocket" => "Socket", + "rb_cString" => "String", + "rb_cStruct" => "Struct", + "rb_cSymbol" => "Symbol", + "rb_cThread" => "Thread", + "rb_cTime" => "Time", + "rb_cTrueClass" => "TrueClass", + + "rb_eArgError" => "ArgError", + "rb_eEOFError" => "EOFError", + "rb_eException" => "Exception", + "rb_eFatal" => "fatal", + "rb_eFloatDomainError" => "FloatDomainError", + "rb_eIOError" => "IOError", + "rb_eIndexError" => "IndexError", + "rb_eInterrupt" => "Interrupt", + "rb_eLoadError" => "LoadError", + "rb_eNameError" => "NameError", + "rb_eNoMemError" => "NoMemError", + "rb_eNotImpError" => "NotImpError", + "rb_eRangeError" => "RangeError", + "rb_eRuntimeError" => "RuntimeError", + "rb_eScriptError" => "ScriptError", + "rb_eSecurityError" => "SecurityError", + "rb_eSignal" => "SignalException", + "rb_eStandardError" => "StandardError", + "rb_eSyntaxError" => "SyntaxError", + "rb_eSystemCallError" => "SystemCallError", + "rb_eSystemExit" => "SystemExit", + "rb_eTypeError" => "TypeError", + "rb_eZeroDivError" => "ZeroDivError", + + "rb_mComparable" => "Comparable", + "rb_mEnumerable" => "Enumerable", + "rb_mErrno" => "Errno", + "rb_mFConst" => "File::Constants", + "rb_mFileTest" => "FileTest", + "rb_mGC" => "GC", + "rb_mKernel" => "Kernel", + "rb_mMath" => "Math", + "rb_mProcess" => "Process" + } + +end diff --git a/jni/ruby/lib/rdoc/markdown.rb b/jni/ruby/lib/rdoc/markdown.rb new file mode 100644 index 0000000..033fc2b --- /dev/null +++ b/jni/ruby/lib/rdoc/markdown.rb @@ -0,0 +1,16133 @@ +# coding: UTF-8 +# :markup: markdown + +## +# RDoc::Markdown as described by the [markdown syntax][syntax]. +# +# To choose Markdown as your only default format see +# RDoc::Options@Saved+Options for instructions on setting up a `.doc_options` +# file to store your project default. +# +# ## Usage +# +# Here is a brief example of using this parse to read a markdown file by hand. +# +# data = File.read("README.md") +# formatter = RDoc::Markup::ToHtml.new(RDoc::Options.new, nil) +# html = RDoc::Markdown.parse(data).accept(@formatter) +# +# # do something with html +# +# ## Extensions +# +# The following markdown extensions are supported by the parser, but not all +# are used in RDoc output by default. +# +# ### RDoc +# +# The RDoc Markdown parser has the following built-in behaviors that cannot be +# disabled. +# +# Underscores embedded in words are never interpreted as emphasis. (While the +# [markdown dingus][dingus] emphasizes in-word underscores, neither the +# Markdown syntax nor MarkdownTest mention this behavior.) +# +# For HTML output, RDoc always auto-links bare URLs. +# +# ### Break on Newline +# +# The break_on_newline extension converts all newlines into hard line breaks +# as in [Github Flavored Markdown][GFM]. This extension is disabled by +# default. +# +# ### CSS +# +# The #css extension enables CSS blocks to be included in the output, but they +# are not used for any built-in RDoc output format. This extension is disabled +# by default. +# +# Example: +# +# <style type="text/css"> +# h1 { font-size: 3em } +# </style> +# +# ### Definition Lists +# +# The definition_lists extension allows definition lists using the [PHP +# Markdown Extra syntax][PHPE], but only one label and definition are supported +# at this time. This extension is enabled by default. +# +# Example: +# +# ``` +# cat +# : A small furry mammal +# that seems to sleep a lot +# +# ant +# : A little insect that is known +# to enjoy picnics +# +# ``` +# +# Produces: +# +# cat +# : A small furry mammal +# that seems to sleep a lot +# +# ant +# : A little insect that is known +# to enjoy picnics +# +# ### Github +# +# The #github extension enables a partial set of [Github Flavored Markdown] +# [GFM]. This extension is enabled by default. +# +# Supported github extensions include: +# +# #### Fenced code blocks +# +# Use ` ``` ` around a block of code instead of indenting it four spaces. +# +# #### Syntax highlighting +# +# Use ` ``` ruby ` as the start of a code fence to add syntax highlighting. +# (Currently only `ruby` syntax is supported). +# +# ### HTML +# +# Enables raw HTML to be included in the output. This extension is enabled by +# default. +# +# Example: +# +# <table> +# ... +# </table> +# +# ### Notes +# +# The #notes extension enables footnote support. This extension is enabled by +# default. +# +# Example: +# +# Here is some text[^1] including an inline footnote ^[for short footnotes] +# +# ... +# +# [^1]: With the footnote text down at the bottom +# +# Produces: +# +# Here is some text[^1] including an inline footnote ^[for short footnotes] +# +# [^1]: With the footnote text down at the bottom +# +# ## Limitations +# +# * Link titles are not used +# * Footnotes are collapsed into a single paragraph +# +# ## Author +# +# This markdown parser is a port to kpeg from [peg-markdown][pegmarkdown] by +# John MacFarlane. +# +# It is used under the MIT license: +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# +# The port to kpeg was performed by Eric Hodel and Evan Phoenix +# +# [dingus]: http://daringfireball.net/projects/markdown/dingus +# [GFM]: http://github.github.com/github-flavored-markdown/ +# [pegmarkdown]: https://github.com/jgm/peg-markdown +# [PHPE]: http://michelf.com/projects/php-markdown/extra/#def-list +# [syntax]: http://daringfireball.net/projects/markdown/syntax +#-- +# Last updated to jgm/peg-markdown commit 8f8fc22ef0 +class RDoc::Markdown + # :stopdoc: + + # This is distinct from setup_parser so that a standalone parser + # can redefine #initialize and still have access to the proper + # parser setup code. + def initialize(str, debug=false) + setup_parser(str, debug) + end + + + + # Prepares for parsing +str+. If you define a custom initialize you must + # call this method before #parse + def setup_parser(str, debug=false) + set_string str, 0 + @memoizations = Hash.new { |h,k| h[k] = {} } + @result = nil + @failed_rule = nil + @failing_rule_offset = -1 + + setup_foreign_grammar + end + + attr_reader :string + attr_reader :failing_rule_offset + attr_accessor :result, :pos + + def current_column(target=pos) + if c = string.rindex("\n", target-1) + return target - c - 1 + end + + target + 1 + end + + def current_line(target=pos) + cur_offset = 0 + cur_line = 0 + + string.each_line do |line| + cur_line += 1 + cur_offset += line.size + return cur_line if cur_offset >= target + end + + -1 + end + + def lines + lines = [] + string.each_line { |l| lines << l } + lines + end + + + + def get_text(start) + @string[start..@pos-1] + end + + # Sets the string and current parsing position for the parser. + def set_string string, pos + @string = string + @string_size = string ? string.size : 0 + @pos = pos + end + + def show_pos + width = 10 + if @pos < width + "#{@pos} (\"#{@string[0,@pos]}\" @ \"#{@string[@pos,width]}\")" + else + "#{@pos} (\"... #{@string[@pos - width, width]}\" @ \"#{@string[@pos,width]}\")" + end + end + + def failure_info + l = current_line @failing_rule_offset + c = current_column @failing_rule_offset + + if @failed_rule.kind_of? Symbol + info = self.class::Rules[@failed_rule] + "line #{l}, column #{c}: failed rule '#{info.name}' = '#{info.rendered}'" + else + "line #{l}, column #{c}: failed rule '#{@failed_rule}'" + end + end + + def failure_caret + l = current_line @failing_rule_offset + c = current_column @failing_rule_offset + + line = lines[l-1] + "#{line}\n#{' ' * (c - 1)}^" + end + + def failure_character + l = current_line @failing_rule_offset + c = current_column @failing_rule_offset + lines[l-1][c-1, 1] + end + + def failure_oneline + l = current_line @failing_rule_offset + c = current_column @failing_rule_offset + + char = lines[l-1][c-1, 1] + + if @failed_rule.kind_of? Symbol + info = self.class::Rules[@failed_rule] + "@#{l}:#{c} failed rule '#{info.name}', got '#{char}'" + else + "@#{l}:#{c} failed rule '#{@failed_rule}', got '#{char}'" + end + end + + class ParseError < RuntimeError + end + + def raise_error + raise ParseError, failure_oneline + end + + def show_error(io=STDOUT) + error_pos = @failing_rule_offset + line_no = current_line(error_pos) + col_no = current_column(error_pos) + + io.puts "On line #{line_no}, column #{col_no}:" + + if @failed_rule.kind_of? Symbol + info = self.class::Rules[@failed_rule] + io.puts "Failed to match '#{info.rendered}' (rule '#{info.name}')" + else + io.puts "Failed to match rule '#{@failed_rule}'" + end + + io.puts "Got: #{string[error_pos,1].inspect}" + line = lines[line_no-1] + io.puts "=> #{line}" + io.print(" " * (col_no + 3)) + io.puts "^" + end + + def set_failed_rule(name) + if @pos > @failing_rule_offset + @failed_rule = name + @failing_rule_offset = @pos + end + end + + attr_reader :failed_rule + + def match_string(str) + len = str.size + if @string[pos,len] == str + @pos += len + return str + end + + return nil + end + + def scan(reg) + if m = reg.match(@string[@pos..-1]) + width = m.end(0) + @pos += width + return true + end + + return nil + end + + if "".respond_to? :ord + def get_byte + if @pos >= @string_size + return nil + end + + s = @string[@pos].ord + @pos += 1 + s + end + else + def get_byte + if @pos >= @string_size + return nil + end + + s = @string[@pos] + @pos += 1 + s + end + end + + def parse(rule=nil) + # We invoke the rules indirectly via apply + # instead of by just calling them as methods because + # if the rules use left recursion, apply needs to + # manage that. + + if !rule + apply(:_root) + else + method = rule.gsub("-","_hyphen_") + apply :"_#{method}" + end + end + + class MemoEntry + def initialize(ans, pos) + @ans = ans + @pos = pos + @result = nil + @set = false + @left_rec = false + end + + attr_reader :ans, :pos, :result, :set + attr_accessor :left_rec + + def move!(ans, pos, result) + @ans = ans + @pos = pos + @result = result + @set = true + @left_rec = false + end + end + + def external_invoke(other, rule, *args) + old_pos = @pos + old_string = @string + + set_string other.string, other.pos + + begin + if val = __send__(rule, *args) + other.pos = @pos + other.result = @result + else + other.set_failed_rule "#{self.class}##{rule}" + end + val + ensure + set_string old_string, old_pos + end + end + + def apply_with_args(rule, *args) + memo_key = [rule, args] + if m = @memoizations[memo_key][@pos] + @pos = m.pos + if !m.set + m.left_rec = true + return nil + end + + @result = m.result + + return m.ans + else + m = MemoEntry.new(nil, @pos) + @memoizations[memo_key][@pos] = m + start_pos = @pos + + ans = __send__ rule, *args + + lr = m.left_rec + + m.move! ans, @pos, @result + + # Don't bother trying to grow the left recursion + # if it's failing straight away (thus there is no seed) + if ans and lr + return grow_lr(rule, args, start_pos, m) + else + return ans + end + + return ans + end + end + + def apply(rule) + if m = @memoizations[rule][@pos] + @pos = m.pos + if !m.set + m.left_rec = true + return nil + end + + @result = m.result + + return m.ans + else + m = MemoEntry.new(nil, @pos) + @memoizations[rule][@pos] = m + start_pos = @pos + + ans = __send__ rule + + lr = m.left_rec + + m.move! ans, @pos, @result + + # Don't bother trying to grow the left recursion + # if it's failing straight away (thus there is no seed) + if ans and lr + return grow_lr(rule, nil, start_pos, m) + else + return ans + end + + return ans + end + end + + def grow_lr(rule, args, start_pos, m) + while true + @pos = start_pos + @result = m.result + + if args + ans = __send__ rule, *args + else + ans = __send__ rule + end + return nil unless ans + + break if @pos <= m.pos + + m.move! ans, @pos, @result + end + + @result = m.result + @pos = m.pos + return m.ans + end + + class RuleInfo + def initialize(name, rendered) + @name = name + @rendered = rendered + end + + attr_reader :name, :rendered + end + + def self.rule_info(name, rendered) + RuleInfo.new(name, rendered) + end + + + # :startdoc: + + + + require 'rubygems' + require 'rdoc' + require 'rdoc/markup/to_joined_paragraph' + require 'rdoc/markdown/entities' + + if RUBY_VERSION > '1.9' then + require 'rdoc/markdown/literals_1_9' + else + require 'rdoc/markdown/literals_1_8' + end + + ## + # Supported extensions + + EXTENSIONS = [] + + ## + # Extensions enabled by default + + DEFAULT_EXTENSIONS = [ + :definition_lists, + :github, + :html, + :notes, + ] + + # :section: Extensions + + ## + # Creates extension methods for the `name` extension to enable and disable + # the extension and to query if they are active. + + def self.extension name + EXTENSIONS << name + + define_method "#{name}?" do + extension? name + end + + define_method "#{name}=" do |enable| + extension name, enable + end + end + + ## + # Converts all newlines into hard breaks + + extension :break_on_newline + + ## + # Allow style blocks + + extension :css + + ## + # Allow PHP Markdown Extras style definition lists + + extension :definition_lists + + ## + # Allow Github Flavored Markdown + + extension :github + + ## + # Allow HTML + + extension :html + + ## + # Enables the notes extension + + extension :notes + + # :section: + + ## + # Parses the `markdown` document into an RDoc::Document using the default + # extensions. + + def self.parse markdown + parser = new + + parser.parse markdown + end + + # TODO remove when kpeg 0.10 is released + alias orig_initialize initialize # :nodoc: + + ## + # Creates a new markdown parser that enables the given +extensions+. + + def initialize extensions = DEFAULT_EXTENSIONS, debug = false + @debug = debug + @formatter = RDoc::Markup::ToJoinedParagraph.new + @extensions = extensions + + @references = nil + @unlinked_references = nil + + @footnotes = nil + @note_order = nil + end + + ## + # Wraps `text` in emphasis for rdoc inline formatting + + def emphasis text + if text =~ /\A[a-z\d.\/]+\z/i then + "_#{text}_" + else + "<em>#{text}</em>" + end + end + + ## + # :category: Extensions + # + # Is the extension `name` enabled? + + def extension? name + @extensions.include? name + end + + ## + # :category: Extensions + # + # Enables or disables the extension with `name` + + def extension name, enable + if enable then + @extensions |= [name] + else + @extensions -= [name] + end + end + + ## + # Parses `text` in a clone of this parser. This is used for handling nested + # lists the same way as markdown_parser. + + def inner_parse text # :nodoc: + parser = clone + + parser.setup_parser text, @debug + + parser.peg_parse + + doc = parser.result + + doc.accept @formatter + + doc.parts + end + + ## + # Finds a link reference for `label` and creates a new link to it with + # `content` as the link text. If `label` was not encountered in the + # reference-gathering parser pass the label and content are reconstructed + # with the linking `text` (usually whitespace). + + def link_to content, label = content, text = nil + raise 'enable notes extension' if + content.start_with? '^' and label.equal? content + + if ref = @references[label] then + "{#{content}}[#{ref}]" + elsif label.equal? content then + "[#{content}]#{text}" + else + "[#{content}]#{text}[#{label}]" + end + end + + ## + # Creates an RDoc::Markup::ListItem by parsing the `unparsed` content from + # the first parsing pass. + + def list_item_from unparsed + parsed = inner_parse unparsed.join + RDoc::Markup::ListItem.new nil, *parsed + end + + ## + # Stores `label` as a note and fills in previously unknown note references. + + def note label + #foottext = "rdoc-label:foottext-#{label}:footmark-#{label}" + + #ref.replace foottext if ref = @unlinked_notes.delete(label) + + @notes[label] = foottext + + #"{^1}[rdoc-label:footmark-#{label}:foottext-#{label}] " + end + + ## + # Creates a new link for the footnote `reference` and adds the reference to + # the note order list for proper display at the end of the document. + + def note_for ref + @note_order << ref + + label = @note_order.length + + "{*#{label}}[rdoc-label:foottext-#{label}:footmark-#{label}]" + end + + ## + # The internal kpeg parse method + + alias peg_parse parse # :nodoc: + + ## + # Creates an RDoc::Markup::Paragraph from `parts` and including + # extension-specific behavior + + def paragraph parts + parts = parts.map do |part| + if "\n" == part then + RDoc::Markup::HardBreak.new + else + part + end + end if break_on_newline? + + RDoc::Markup::Paragraph.new(*parts) + end + + ## + # Parses `markdown` into an RDoc::Document + + def parse markdown + @references = {} + @unlinked_references = {} + + markdown += "\n\n" + + setup_parser markdown, @debug + peg_parse 'References' + + if notes? then + @footnotes = {} + + setup_parser markdown, @debug + peg_parse 'Notes' + + # using note_order on the first pass would be a bug + @note_order = [] + end + + setup_parser markdown, @debug + peg_parse + + doc = result + + if notes? and not @footnotes.empty? then + doc << RDoc::Markup::Rule.new(1) + + @note_order.each_with_index do |ref, index| + label = index + 1 + note = @footnotes[ref] + + link = "{^#{label}}[rdoc-label:footmark-#{label}:foottext-#{label}] " + note.parts.unshift link + + doc << note + end + end + + doc.accept @formatter + + doc + end + + ## + # Stores `label` as a reference to `link` and fills in previously unknown + # link references. + + def reference label, link + if ref = @unlinked_references.delete(label) then + ref.replace link + end + + @references[label] = link + end + + ## + # Wraps `text` in strong markup for rdoc inline formatting + + def strong text + if text =~ /\A[a-z\d.\/-]+\z/i then + "*#{text}*" + else + "<b>#{text}</b>" + end + end + + + # :stopdoc: + def setup_foreign_grammar + @_grammar_literals = RDoc::Markdown::Literals.new(nil) + end + + # root = Doc + def _root + _tmp = apply(:_Doc) + set_failed_rule :_root unless _tmp + return _tmp + end + + # Doc = BOM? Block*:a { RDoc::Markup::Document.new(*a.compact) } + def _Doc + + _save = self.pos + while true # sequence + _save1 = self.pos + _tmp = apply(:_BOM) + unless _tmp + _tmp = true + self.pos = _save1 + end + unless _tmp + self.pos = _save + break + end + _ary = [] + while true + _tmp = apply(:_Block) + _ary << @result if _tmp + break unless _tmp + end + _tmp = true + @result = _ary + a = @result + unless _tmp + self.pos = _save + break + end + @result = begin; RDoc::Markup::Document.new(*a.compact) ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_Doc unless _tmp + return _tmp + end + + # Block = @BlankLine* (BlockQuote | Verbatim | CodeFence | Note | Reference | HorizontalRule | Heading | OrderedList | BulletList | DefinitionList | HtmlBlock | StyleBlock | Para | Plain) + def _Block + + _save = self.pos + while true # sequence + while true + _tmp = _BlankLine() + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + + _save2 = self.pos + while true # choice + _tmp = apply(:_BlockQuote) + break if _tmp + self.pos = _save2 + _tmp = apply(:_Verbatim) + break if _tmp + self.pos = _save2 + _tmp = apply(:_CodeFence) + break if _tmp + self.pos = _save2 + _tmp = apply(:_Note) + break if _tmp + self.pos = _save2 + _tmp = apply(:_Reference) + break if _tmp + self.pos = _save2 + _tmp = apply(:_HorizontalRule) + break if _tmp + self.pos = _save2 + _tmp = apply(:_Heading) + break if _tmp + self.pos = _save2 + _tmp = apply(:_OrderedList) + break if _tmp + self.pos = _save2 + _tmp = apply(:_BulletList) + break if _tmp + self.pos = _save2 + _tmp = apply(:_DefinitionList) + break if _tmp + self.pos = _save2 + _tmp = apply(:_HtmlBlock) + break if _tmp + self.pos = _save2 + _tmp = apply(:_StyleBlock) + break if _tmp + self.pos = _save2 + _tmp = apply(:_Para) + break if _tmp + self.pos = _save2 + _tmp = apply(:_Plain) + break if _tmp + self.pos = _save2 + break + end # end choice + + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_Block unless _tmp + return _tmp + end + + # Para = @NonindentSpace Inlines:a @BlankLine+ { paragraph a } + def _Para + + _save = self.pos + while true # sequence + _tmp = _NonindentSpace() + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Inlines) + a = @result + unless _tmp + self.pos = _save + break + end + _save1 = self.pos + _tmp = _BlankLine() + if _tmp + while true + _tmp = _BlankLine() + break unless _tmp + end + _tmp = true + else + self.pos = _save1 + end + unless _tmp + self.pos = _save + break + end + @result = begin; paragraph a ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_Para unless _tmp + return _tmp + end + + # Plain = Inlines:a { paragraph a } + def _Plain + + _save = self.pos + while true # sequence + _tmp = apply(:_Inlines) + a = @result + unless _tmp + self.pos = _save + break + end + @result = begin; paragraph a ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_Plain unless _tmp + return _tmp + end + + # AtxInline = !@Newline !(@Sp? /#*/ @Sp @Newline) Inline + def _AtxInline + + _save = self.pos + while true # sequence + _save1 = self.pos + _tmp = _Newline() + _tmp = _tmp ? nil : true + self.pos = _save1 + unless _tmp + self.pos = _save + break + end + _save2 = self.pos + + _save3 = self.pos + while true # sequence + _save4 = self.pos + _tmp = _Sp() + unless _tmp + _tmp = true + self.pos = _save4 + end + unless _tmp + self.pos = _save3 + break + end + _tmp = scan(/\A(?-mix:#*)/) + unless _tmp + self.pos = _save3 + break + end + _tmp = _Sp() + unless _tmp + self.pos = _save3 + break + end + _tmp = _Newline() + unless _tmp + self.pos = _save3 + end + break + end # end sequence + + _tmp = _tmp ? nil : true + self.pos = _save2 + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Inline) + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_AtxInline unless _tmp + return _tmp + end + + # AtxStart = < /\#{1,6}/ > { text.length } + def _AtxStart + + _save = self.pos + while true # sequence + _text_start = self.pos + _tmp = scan(/\A(?-mix:\#{1,6})/) + if _tmp + text = get_text(_text_start) + end + unless _tmp + self.pos = _save + break + end + @result = begin; text.length ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_AtxStart unless _tmp + return _tmp + end + + # AtxHeading = AtxStart:s @Sp? AtxInline+:a (@Sp? /#*/ @Sp)? @Newline { RDoc::Markup::Heading.new(s, a.join) } + def _AtxHeading + + _save = self.pos + while true # sequence + _tmp = apply(:_AtxStart) + s = @result + unless _tmp + self.pos = _save + break + end + _save1 = self.pos + _tmp = _Sp() + unless _tmp + _tmp = true + self.pos = _save1 + end + unless _tmp + self.pos = _save + break + end + _save2 = self.pos + _ary = [] + _tmp = apply(:_AtxInline) + if _tmp + _ary << @result + while true + _tmp = apply(:_AtxInline) + _ary << @result if _tmp + break unless _tmp + end + _tmp = true + @result = _ary + else + self.pos = _save2 + end + a = @result + unless _tmp + self.pos = _save + break + end + _save3 = self.pos + + _save4 = self.pos + while true # sequence + _save5 = self.pos + _tmp = _Sp() + unless _tmp + _tmp = true + self.pos = _save5 + end + unless _tmp + self.pos = _save4 + break + end + _tmp = scan(/\A(?-mix:#*)/) + unless _tmp + self.pos = _save4 + break + end + _tmp = _Sp() + unless _tmp + self.pos = _save4 + end + break + end # end sequence + + unless _tmp + _tmp = true + self.pos = _save3 + end + unless _tmp + self.pos = _save + break + end + _tmp = _Newline() + unless _tmp + self.pos = _save + break + end + @result = begin; RDoc::Markup::Heading.new(s, a.join) ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_AtxHeading unless _tmp + return _tmp + end + + # SetextHeading = (SetextHeading1 | SetextHeading2) + def _SetextHeading + + _save = self.pos + while true # choice + _tmp = apply(:_SetextHeading1) + break if _tmp + self.pos = _save + _tmp = apply(:_SetextHeading2) + break if _tmp + self.pos = _save + break + end # end choice + + set_failed_rule :_SetextHeading unless _tmp + return _tmp + end + + # SetextBottom1 = /={3,}/ @Newline + def _SetextBottom1 + + _save = self.pos + while true # sequence + _tmp = scan(/\A(?-mix:={3,})/) + unless _tmp + self.pos = _save + break + end + _tmp = _Newline() + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_SetextBottom1 unless _tmp + return _tmp + end + + # SetextBottom2 = /-{3,}/ @Newline + def _SetextBottom2 + + _save = self.pos + while true # sequence + _tmp = scan(/\A(?-mix:-{3,})/) + unless _tmp + self.pos = _save + break + end + _tmp = _Newline() + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_SetextBottom2 unless _tmp + return _tmp + end + + # SetextHeading1 = &(@RawLine SetextBottom1) @StartList:a (!@Endline Inline:b { a << b })+ @Sp? @Newline SetextBottom1 { RDoc::Markup::Heading.new(1, a.join) } + def _SetextHeading1 + + _save = self.pos + while true # sequence + _save1 = self.pos + + _save2 = self.pos + while true # sequence + _tmp = _RawLine() + unless _tmp + self.pos = _save2 + break + end + _tmp = apply(:_SetextBottom1) + unless _tmp + self.pos = _save2 + end + break + end # end sequence + + self.pos = _save1 + unless _tmp + self.pos = _save + break + end + _tmp = _StartList() + a = @result + unless _tmp + self.pos = _save + break + end + _save3 = self.pos + + _save4 = self.pos + while true # sequence + _save5 = self.pos + _tmp = _Endline() + _tmp = _tmp ? nil : true + self.pos = _save5 + unless _tmp + self.pos = _save4 + break + end + _tmp = apply(:_Inline) + b = @result + unless _tmp + self.pos = _save4 + break + end + @result = begin; a << b ; end + _tmp = true + unless _tmp + self.pos = _save4 + end + break + end # end sequence + + if _tmp + while true + + _save6 = self.pos + while true # sequence + _save7 = self.pos + _tmp = _Endline() + _tmp = _tmp ? nil : true + self.pos = _save7 + unless _tmp + self.pos = _save6 + break + end + _tmp = apply(:_Inline) + b = @result + unless _tmp + self.pos = _save6 + break + end + @result = begin; a << b ; end + _tmp = true + unless _tmp + self.pos = _save6 + end + break + end # end sequence + + break unless _tmp + end + _tmp = true + else + self.pos = _save3 + end + unless _tmp + self.pos = _save + break + end + _save8 = self.pos + _tmp = _Sp() + unless _tmp + _tmp = true + self.pos = _save8 + end + unless _tmp + self.pos = _save + break + end + _tmp = _Newline() + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_SetextBottom1) + unless _tmp + self.pos = _save + break + end + @result = begin; RDoc::Markup::Heading.new(1, a.join) ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_SetextHeading1 unless _tmp + return _tmp + end + + # SetextHeading2 = &(@RawLine SetextBottom2) @StartList:a (!@Endline Inline:b { a << b })+ @Sp? @Newline SetextBottom2 { RDoc::Markup::Heading.new(2, a.join) } + def _SetextHeading2 + + _save = self.pos + while true # sequence + _save1 = self.pos + + _save2 = self.pos + while true # sequence + _tmp = _RawLine() + unless _tmp + self.pos = _save2 + break + end + _tmp = apply(:_SetextBottom2) + unless _tmp + self.pos = _save2 + end + break + end # end sequence + + self.pos = _save1 + unless _tmp + self.pos = _save + break + end + _tmp = _StartList() + a = @result + unless _tmp + self.pos = _save + break + end + _save3 = self.pos + + _save4 = self.pos + while true # sequence + _save5 = self.pos + _tmp = _Endline() + _tmp = _tmp ? nil : true + self.pos = _save5 + unless _tmp + self.pos = _save4 + break + end + _tmp = apply(:_Inline) + b = @result + unless _tmp + self.pos = _save4 + break + end + @result = begin; a << b ; end + _tmp = true + unless _tmp + self.pos = _save4 + end + break + end # end sequence + + if _tmp + while true + + _save6 = self.pos + while true # sequence + _save7 = self.pos + _tmp = _Endline() + _tmp = _tmp ? nil : true + self.pos = _save7 + unless _tmp + self.pos = _save6 + break + end + _tmp = apply(:_Inline) + b = @result + unless _tmp + self.pos = _save6 + break + end + @result = begin; a << b ; end + _tmp = true + unless _tmp + self.pos = _save6 + end + break + end # end sequence + + break unless _tmp + end + _tmp = true + else + self.pos = _save3 + end + unless _tmp + self.pos = _save + break + end + _save8 = self.pos + _tmp = _Sp() + unless _tmp + _tmp = true + self.pos = _save8 + end + unless _tmp + self.pos = _save + break + end + _tmp = _Newline() + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_SetextBottom2) + unless _tmp + self.pos = _save + break + end + @result = begin; RDoc::Markup::Heading.new(2, a.join) ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_SetextHeading2 unless _tmp + return _tmp + end + + # Heading = (SetextHeading | AtxHeading) + def _Heading + + _save = self.pos + while true # choice + _tmp = apply(:_SetextHeading) + break if _tmp + self.pos = _save + _tmp = apply(:_AtxHeading) + break if _tmp + self.pos = _save + break + end # end choice + + set_failed_rule :_Heading unless _tmp + return _tmp + end + + # BlockQuote = BlockQuoteRaw:a { RDoc::Markup::BlockQuote.new(*a) } + def _BlockQuote + + _save = self.pos + while true # sequence + _tmp = apply(:_BlockQuoteRaw) + a = @result + unless _tmp + self.pos = _save + break + end + @result = begin; RDoc::Markup::BlockQuote.new(*a) ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_BlockQuote unless _tmp + return _tmp + end + + # BlockQuoteRaw = @StartList:a (">" " "? Line:l { a << l } (!">" !@BlankLine Line:c { a << c })* (@BlankLine:n { a << n })*)+ { inner_parse a.join } + def _BlockQuoteRaw + + _save = self.pos + while true # sequence + _tmp = _StartList() + a = @result + unless _tmp + self.pos = _save + break + end + _save1 = self.pos + + _save2 = self.pos + while true # sequence + _tmp = match_string(">") + unless _tmp + self.pos = _save2 + break + end + _save3 = self.pos + _tmp = match_string(" ") + unless _tmp + _tmp = true + self.pos = _save3 + end + unless _tmp + self.pos = _save2 + break + end + _tmp = apply(:_Line) + l = @result + unless _tmp + self.pos = _save2 + break + end + @result = begin; a << l ; end + _tmp = true + unless _tmp + self.pos = _save2 + break + end + while true + + _save5 = self.pos + while true # sequence + _save6 = self.pos + _tmp = match_string(">") + _tmp = _tmp ? nil : true + self.pos = _save6 + unless _tmp + self.pos = _save5 + break + end + _save7 = self.pos + _tmp = _BlankLine() + _tmp = _tmp ? nil : true + self.pos = _save7 + unless _tmp + self.pos = _save5 + break + end + _tmp = apply(:_Line) + c = @result + unless _tmp + self.pos = _save5 + break + end + @result = begin; a << c ; end + _tmp = true + unless _tmp + self.pos = _save5 + end + break + end # end sequence + + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save2 + break + end + while true + + _save9 = self.pos + while true # sequence + _tmp = _BlankLine() + n = @result + unless _tmp + self.pos = _save9 + break + end + @result = begin; a << n ; end + _tmp = true + unless _tmp + self.pos = _save9 + end + break + end # end sequence + + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save2 + end + break + end # end sequence + + if _tmp + while true + + _save10 = self.pos + while true # sequence + _tmp = match_string(">") + unless _tmp + self.pos = _save10 + break + end + _save11 = self.pos + _tmp = match_string(" ") + unless _tmp + _tmp = true + self.pos = _save11 + end + unless _tmp + self.pos = _save10 + break + end + _tmp = apply(:_Line) + l = @result + unless _tmp + self.pos = _save10 + break + end + @result = begin; a << l ; end + _tmp = true + unless _tmp + self.pos = _save10 + break + end + while true + + _save13 = self.pos + while true # sequence + _save14 = self.pos + _tmp = match_string(">") + _tmp = _tmp ? nil : true + self.pos = _save14 + unless _tmp + self.pos = _save13 + break + end + _save15 = self.pos + _tmp = _BlankLine() + _tmp = _tmp ? nil : true + self.pos = _save15 + unless _tmp + self.pos = _save13 + break + end + _tmp = apply(:_Line) + c = @result + unless _tmp + self.pos = _save13 + break + end + @result = begin; a << c ; end + _tmp = true + unless _tmp + self.pos = _save13 + end + break + end # end sequence + + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save10 + break + end + while true + + _save17 = self.pos + while true # sequence + _tmp = _BlankLine() + n = @result + unless _tmp + self.pos = _save17 + break + end + @result = begin; a << n ; end + _tmp = true + unless _tmp + self.pos = _save17 + end + break + end # end sequence + + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save10 + end + break + end # end sequence + + break unless _tmp + end + _tmp = true + else + self.pos = _save1 + end + unless _tmp + self.pos = _save + break + end + @result = begin; inner_parse a.join ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_BlockQuoteRaw unless _tmp + return _tmp + end + + # NonblankIndentedLine = !@BlankLine IndentedLine + def _NonblankIndentedLine + + _save = self.pos + while true # sequence + _save1 = self.pos + _tmp = _BlankLine() + _tmp = _tmp ? nil : true + self.pos = _save1 + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_IndentedLine) + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_NonblankIndentedLine unless _tmp + return _tmp + end + + # VerbatimChunk = @BlankLine*:a NonblankIndentedLine+:b { a.concat b } + def _VerbatimChunk + + _save = self.pos + while true # sequence + _ary = [] + while true + _tmp = _BlankLine() + _ary << @result if _tmp + break unless _tmp + end + _tmp = true + @result = _ary + a = @result + unless _tmp + self.pos = _save + break + end + _save2 = self.pos + _ary = [] + _tmp = apply(:_NonblankIndentedLine) + if _tmp + _ary << @result + while true + _tmp = apply(:_NonblankIndentedLine) + _ary << @result if _tmp + break unless _tmp + end + _tmp = true + @result = _ary + else + self.pos = _save2 + end + b = @result + unless _tmp + self.pos = _save + break + end + @result = begin; a.concat b ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_VerbatimChunk unless _tmp + return _tmp + end + + # Verbatim = VerbatimChunk+:a { RDoc::Markup::Verbatim.new(*a.flatten) } + def _Verbatim + + _save = self.pos + while true # sequence + _save1 = self.pos + _ary = [] + _tmp = apply(:_VerbatimChunk) + if _tmp + _ary << @result + while true + _tmp = apply(:_VerbatimChunk) + _ary << @result if _tmp + break unless _tmp + end + _tmp = true + @result = _ary + else + self.pos = _save1 + end + a = @result + unless _tmp + self.pos = _save + break + end + @result = begin; RDoc::Markup::Verbatim.new(*a.flatten) ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_Verbatim unless _tmp + return _tmp + end + + # HorizontalRule = @NonindentSpace ("*" @Sp "*" @Sp "*" (@Sp "*")* | "-" @Sp "-" @Sp "-" (@Sp "-")* | "_" @Sp "_" @Sp "_" (@Sp "_")*) @Sp @Newline @BlankLine+ { RDoc::Markup::Rule.new 1 } + def _HorizontalRule + + _save = self.pos + while true # sequence + _tmp = _NonindentSpace() + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + + _save2 = self.pos + while true # sequence + _tmp = match_string("*") + unless _tmp + self.pos = _save2 + break + end + _tmp = _Sp() + unless _tmp + self.pos = _save2 + break + end + _tmp = match_string("*") + unless _tmp + self.pos = _save2 + break + end + _tmp = _Sp() + unless _tmp + self.pos = _save2 + break + end + _tmp = match_string("*") + unless _tmp + self.pos = _save2 + break + end + while true + + _save4 = self.pos + while true # sequence + _tmp = _Sp() + unless _tmp + self.pos = _save4 + break + end + _tmp = match_string("*") + unless _tmp + self.pos = _save4 + end + break + end # end sequence + + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save2 + end + break + end # end sequence + + break if _tmp + self.pos = _save1 + + _save5 = self.pos + while true # sequence + _tmp = match_string("-") + unless _tmp + self.pos = _save5 + break + end + _tmp = _Sp() + unless _tmp + self.pos = _save5 + break + end + _tmp = match_string("-") + unless _tmp + self.pos = _save5 + break + end + _tmp = _Sp() + unless _tmp + self.pos = _save5 + break + end + _tmp = match_string("-") + unless _tmp + self.pos = _save5 + break + end + while true + + _save7 = self.pos + while true # sequence + _tmp = _Sp() + unless _tmp + self.pos = _save7 + break + end + _tmp = match_string("-") + unless _tmp + self.pos = _save7 + end + break + end # end sequence + + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save5 + end + break + end # end sequence + + break if _tmp + self.pos = _save1 + + _save8 = self.pos + while true # sequence + _tmp = match_string("_") + unless _tmp + self.pos = _save8 + break + end + _tmp = _Sp() + unless _tmp + self.pos = _save8 + break + end + _tmp = match_string("_") + unless _tmp + self.pos = _save8 + break + end + _tmp = _Sp() + unless _tmp + self.pos = _save8 + break + end + _tmp = match_string("_") + unless _tmp + self.pos = _save8 + break + end + while true + + _save10 = self.pos + while true # sequence + _tmp = _Sp() + unless _tmp + self.pos = _save10 + break + end + _tmp = match_string("_") + unless _tmp + self.pos = _save10 + end + break + end # end sequence + + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save8 + end + break + end # end sequence + + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = _Sp() + unless _tmp + self.pos = _save + break + end + _tmp = _Newline() + unless _tmp + self.pos = _save + break + end + _save11 = self.pos + _tmp = _BlankLine() + if _tmp + while true + _tmp = _BlankLine() + break unless _tmp + end + _tmp = true + else + self.pos = _save11 + end + unless _tmp + self.pos = _save + break + end + @result = begin; RDoc::Markup::Rule.new 1 ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HorizontalRule unless _tmp + return _tmp + end + + # Bullet = !HorizontalRule @NonindentSpace /[+*-]/ @Spacechar+ + def _Bullet + + _save = self.pos + while true # sequence + _save1 = self.pos + _tmp = apply(:_HorizontalRule) + _tmp = _tmp ? nil : true + self.pos = _save1 + unless _tmp + self.pos = _save + break + end + _tmp = _NonindentSpace() + unless _tmp + self.pos = _save + break + end + _tmp = scan(/\A(?-mix:[+*-])/) + unless _tmp + self.pos = _save + break + end + _save2 = self.pos + _tmp = _Spacechar() + if _tmp + while true + _tmp = _Spacechar() + break unless _tmp + end + _tmp = true + else + self.pos = _save2 + end + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_Bullet unless _tmp + return _tmp + end + + # BulletList = &Bullet (ListTight | ListLoose):a { RDoc::Markup::List.new(:BULLET, *a) } + def _BulletList + + _save = self.pos + while true # sequence + _save1 = self.pos + _tmp = apply(:_Bullet) + self.pos = _save1 + unless _tmp + self.pos = _save + break + end + + _save2 = self.pos + while true # choice + _tmp = apply(:_ListTight) + break if _tmp + self.pos = _save2 + _tmp = apply(:_ListLoose) + break if _tmp + self.pos = _save2 + break + end # end choice + + a = @result + unless _tmp + self.pos = _save + break + end + @result = begin; RDoc::Markup::List.new(:BULLET, *a) ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_BulletList unless _tmp + return _tmp + end + + # ListTight = ListItemTight+:a @BlankLine* !(Bullet | Enumerator) { a } + def _ListTight + + _save = self.pos + while true # sequence + _save1 = self.pos + _ary = [] + _tmp = apply(:_ListItemTight) + if _tmp + _ary << @result + while true + _tmp = apply(:_ListItemTight) + _ary << @result if _tmp + break unless _tmp + end + _tmp = true + @result = _ary + else + self.pos = _save1 + end + a = @result + unless _tmp + self.pos = _save + break + end + while true + _tmp = _BlankLine() + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _save3 = self.pos + + _save4 = self.pos + while true # choice + _tmp = apply(:_Bullet) + break if _tmp + self.pos = _save4 + _tmp = apply(:_Enumerator) + break if _tmp + self.pos = _save4 + break + end # end choice + + _tmp = _tmp ? nil : true + self.pos = _save3 + unless _tmp + self.pos = _save + break + end + @result = begin; a ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_ListTight unless _tmp + return _tmp + end + + # ListLoose = @StartList:a (ListItem:b @BlankLine* { a << b })+ { a } + def _ListLoose + + _save = self.pos + while true # sequence + _tmp = _StartList() + a = @result + unless _tmp + self.pos = _save + break + end + _save1 = self.pos + + _save2 = self.pos + while true # sequence + _tmp = apply(:_ListItem) + b = @result + unless _tmp + self.pos = _save2 + break + end + while true + _tmp = _BlankLine() + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save2 + break + end + @result = begin; a << b ; end + _tmp = true + unless _tmp + self.pos = _save2 + end + break + end # end sequence + + if _tmp + while true + + _save4 = self.pos + while true # sequence + _tmp = apply(:_ListItem) + b = @result + unless _tmp + self.pos = _save4 + break + end + while true + _tmp = _BlankLine() + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save4 + break + end + @result = begin; a << b ; end + _tmp = true + unless _tmp + self.pos = _save4 + end + break + end # end sequence + + break unless _tmp + end + _tmp = true + else + self.pos = _save1 + end + unless _tmp + self.pos = _save + break + end + @result = begin; a ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_ListLoose unless _tmp + return _tmp + end + + # ListItem = (Bullet | Enumerator) @StartList:a ListBlock:b { a << b } (ListContinuationBlock:c { a.push(*c) })* { list_item_from a } + def _ListItem + + _save = self.pos + while true # sequence + + _save1 = self.pos + while true # choice + _tmp = apply(:_Bullet) + break if _tmp + self.pos = _save1 + _tmp = apply(:_Enumerator) + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = _StartList() + a = @result + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_ListBlock) + b = @result + unless _tmp + self.pos = _save + break + end + @result = begin; a << b ; end + _tmp = true + unless _tmp + self.pos = _save + break + end + while true + + _save3 = self.pos + while true # sequence + _tmp = apply(:_ListContinuationBlock) + c = @result + unless _tmp + self.pos = _save3 + break + end + @result = begin; a.push(*c) ; end + _tmp = true + unless _tmp + self.pos = _save3 + end + break + end # end sequence + + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + @result = begin; list_item_from a ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_ListItem unless _tmp + return _tmp + end + + # ListItemTight = (Bullet | Enumerator) ListBlock:a (!@BlankLine ListContinuationBlock:b { a.push(*b) })* !ListContinuationBlock { list_item_from a } + def _ListItemTight + + _save = self.pos + while true # sequence + + _save1 = self.pos + while true # choice + _tmp = apply(:_Bullet) + break if _tmp + self.pos = _save1 + _tmp = apply(:_Enumerator) + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_ListBlock) + a = @result + unless _tmp + self.pos = _save + break + end + while true + + _save3 = self.pos + while true # sequence + _save4 = self.pos + _tmp = _BlankLine() + _tmp = _tmp ? nil : true + self.pos = _save4 + unless _tmp + self.pos = _save3 + break + end + _tmp = apply(:_ListContinuationBlock) + b = @result + unless _tmp + self.pos = _save3 + break + end + @result = begin; a.push(*b) ; end + _tmp = true + unless _tmp + self.pos = _save3 + end + break + end # end sequence + + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _save5 = self.pos + _tmp = apply(:_ListContinuationBlock) + _tmp = _tmp ? nil : true + self.pos = _save5 + unless _tmp + self.pos = _save + break + end + @result = begin; list_item_from a ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_ListItemTight unless _tmp + return _tmp + end + + # ListBlock = !@BlankLine Line:a ListBlockLine*:c { [a, *c] } + def _ListBlock + + _save = self.pos + while true # sequence + _save1 = self.pos + _tmp = _BlankLine() + _tmp = _tmp ? nil : true + self.pos = _save1 + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Line) + a = @result + unless _tmp + self.pos = _save + break + end + _ary = [] + while true + _tmp = apply(:_ListBlockLine) + _ary << @result if _tmp + break unless _tmp + end + _tmp = true + @result = _ary + c = @result + unless _tmp + self.pos = _save + break + end + @result = begin; [a, *c] ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_ListBlock unless _tmp + return _tmp + end + + # ListContinuationBlock = @StartList:a @BlankLine* { a << "\n" } (Indent ListBlock:b { a.concat b })+ { a } + def _ListContinuationBlock + + _save = self.pos + while true # sequence + _tmp = _StartList() + a = @result + unless _tmp + self.pos = _save + break + end + while true + _tmp = _BlankLine() + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + @result = begin; a << "\n" ; end + _tmp = true + unless _tmp + self.pos = _save + break + end + _save2 = self.pos + + _save3 = self.pos + while true # sequence + _tmp = apply(:_Indent) + unless _tmp + self.pos = _save3 + break + end + _tmp = apply(:_ListBlock) + b = @result + unless _tmp + self.pos = _save3 + break + end + @result = begin; a.concat b ; end + _tmp = true + unless _tmp + self.pos = _save3 + end + break + end # end sequence + + if _tmp + while true + + _save4 = self.pos + while true # sequence + _tmp = apply(:_Indent) + unless _tmp + self.pos = _save4 + break + end + _tmp = apply(:_ListBlock) + b = @result + unless _tmp + self.pos = _save4 + break + end + @result = begin; a.concat b ; end + _tmp = true + unless _tmp + self.pos = _save4 + end + break + end # end sequence + + break unless _tmp + end + _tmp = true + else + self.pos = _save2 + end + unless _tmp + self.pos = _save + break + end + @result = begin; a ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_ListContinuationBlock unless _tmp + return _tmp + end + + # Enumerator = @NonindentSpace [0-9]+ "." @Spacechar+ + def _Enumerator + + _save = self.pos + while true # sequence + _tmp = _NonindentSpace() + unless _tmp + self.pos = _save + break + end + _save1 = self.pos + _save2 = self.pos + _tmp = get_byte + if _tmp + unless _tmp >= 48 and _tmp <= 57 + self.pos = _save2 + _tmp = nil + end + end + if _tmp + while true + _save3 = self.pos + _tmp = get_byte + if _tmp + unless _tmp >= 48 and _tmp <= 57 + self.pos = _save3 + _tmp = nil + end + end + break unless _tmp + end + _tmp = true + else + self.pos = _save1 + end + unless _tmp + self.pos = _save + break + end + _tmp = match_string(".") + unless _tmp + self.pos = _save + break + end + _save4 = self.pos + _tmp = _Spacechar() + if _tmp + while true + _tmp = _Spacechar() + break unless _tmp + end + _tmp = true + else + self.pos = _save4 + end + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_Enumerator unless _tmp + return _tmp + end + + # OrderedList = &Enumerator (ListTight | ListLoose):a { RDoc::Markup::List.new(:NUMBER, *a) } + def _OrderedList + + _save = self.pos + while true # sequence + _save1 = self.pos + _tmp = apply(:_Enumerator) + self.pos = _save1 + unless _tmp + self.pos = _save + break + end + + _save2 = self.pos + while true # choice + _tmp = apply(:_ListTight) + break if _tmp + self.pos = _save2 + _tmp = apply(:_ListLoose) + break if _tmp + self.pos = _save2 + break + end # end choice + + a = @result + unless _tmp + self.pos = _save + break + end + @result = begin; RDoc::Markup::List.new(:NUMBER, *a) ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_OrderedList unless _tmp + return _tmp + end + + # ListBlockLine = !@BlankLine !(Indent? (Bullet | Enumerator)) !HorizontalRule OptionallyIndentedLine + def _ListBlockLine + + _save = self.pos + while true # sequence + _save1 = self.pos + _tmp = _BlankLine() + _tmp = _tmp ? nil : true + self.pos = _save1 + unless _tmp + self.pos = _save + break + end + _save2 = self.pos + + _save3 = self.pos + while true # sequence + _save4 = self.pos + _tmp = apply(:_Indent) + unless _tmp + _tmp = true + self.pos = _save4 + end + unless _tmp + self.pos = _save3 + break + end + + _save5 = self.pos + while true # choice + _tmp = apply(:_Bullet) + break if _tmp + self.pos = _save5 + _tmp = apply(:_Enumerator) + break if _tmp + self.pos = _save5 + break + end # end choice + + unless _tmp + self.pos = _save3 + end + break + end # end sequence + + _tmp = _tmp ? nil : true + self.pos = _save2 + unless _tmp + self.pos = _save + break + end + _save6 = self.pos + _tmp = apply(:_HorizontalRule) + _tmp = _tmp ? nil : true + self.pos = _save6 + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_OptionallyIndentedLine) + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_ListBlockLine unless _tmp + return _tmp + end + + # HtmlOpenAnchor = "<" Spnl ("a" | "A") Spnl HtmlAttribute* ">" + def _HtmlOpenAnchor + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("a") + break if _tmp + self.pos = _save1 + _tmp = match_string("A") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + while true + _tmp = apply(:_HtmlAttribute) + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlOpenAnchor unless _tmp + return _tmp + end + + # HtmlCloseAnchor = "<" Spnl "/" ("a" | "A") Spnl ">" + def _HtmlCloseAnchor + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string("/") + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("a") + break if _tmp + self.pos = _save1 + _tmp = match_string("A") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlCloseAnchor unless _tmp + return _tmp + end + + # HtmlAnchor = HtmlOpenAnchor (HtmlAnchor | !HtmlCloseAnchor .)* HtmlCloseAnchor + def _HtmlAnchor + + _save = self.pos + while true # sequence + _tmp = apply(:_HtmlOpenAnchor) + unless _tmp + self.pos = _save + break + end + while true + + _save2 = self.pos + while true # choice + _tmp = apply(:_HtmlAnchor) + break if _tmp + self.pos = _save2 + + _save3 = self.pos + while true # sequence + _save4 = self.pos + _tmp = apply(:_HtmlCloseAnchor) + _tmp = _tmp ? nil : true + self.pos = _save4 + unless _tmp + self.pos = _save3 + break + end + _tmp = get_byte + unless _tmp + self.pos = _save3 + end + break + end # end sequence + + break if _tmp + self.pos = _save2 + break + end # end choice + + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_HtmlCloseAnchor) + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlAnchor unless _tmp + return _tmp + end + + # HtmlBlockOpenAddress = "<" Spnl ("address" | "ADDRESS") Spnl HtmlAttribute* ">" + def _HtmlBlockOpenAddress + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("address") + break if _tmp + self.pos = _save1 + _tmp = match_string("ADDRESS") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + while true + _tmp = apply(:_HtmlAttribute) + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockOpenAddress unless _tmp + return _tmp + end + + # HtmlBlockCloseAddress = "<" Spnl "/" ("address" | "ADDRESS") Spnl ">" + def _HtmlBlockCloseAddress + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string("/") + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("address") + break if _tmp + self.pos = _save1 + _tmp = match_string("ADDRESS") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockCloseAddress unless _tmp + return _tmp + end + + # HtmlBlockAddress = HtmlBlockOpenAddress (HtmlBlockAddress | !HtmlBlockCloseAddress .)* HtmlBlockCloseAddress + def _HtmlBlockAddress + + _save = self.pos + while true # sequence + _tmp = apply(:_HtmlBlockOpenAddress) + unless _tmp + self.pos = _save + break + end + while true + + _save2 = self.pos + while true # choice + _tmp = apply(:_HtmlBlockAddress) + break if _tmp + self.pos = _save2 + + _save3 = self.pos + while true # sequence + _save4 = self.pos + _tmp = apply(:_HtmlBlockCloseAddress) + _tmp = _tmp ? nil : true + self.pos = _save4 + unless _tmp + self.pos = _save3 + break + end + _tmp = get_byte + unless _tmp + self.pos = _save3 + end + break + end # end sequence + + break if _tmp + self.pos = _save2 + break + end # end choice + + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_HtmlBlockCloseAddress) + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockAddress unless _tmp + return _tmp + end + + # HtmlBlockOpenBlockquote = "<" Spnl ("blockquote" | "BLOCKQUOTE") Spnl HtmlAttribute* ">" + def _HtmlBlockOpenBlockquote + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("blockquote") + break if _tmp + self.pos = _save1 + _tmp = match_string("BLOCKQUOTE") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + while true + _tmp = apply(:_HtmlAttribute) + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockOpenBlockquote unless _tmp + return _tmp + end + + # HtmlBlockCloseBlockquote = "<" Spnl "/" ("blockquote" | "BLOCKQUOTE") Spnl ">" + def _HtmlBlockCloseBlockquote + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string("/") + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("blockquote") + break if _tmp + self.pos = _save1 + _tmp = match_string("BLOCKQUOTE") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockCloseBlockquote unless _tmp + return _tmp + end + + # HtmlBlockBlockquote = HtmlBlockOpenBlockquote (HtmlBlockBlockquote | !HtmlBlockCloseBlockquote .)* HtmlBlockCloseBlockquote + def _HtmlBlockBlockquote + + _save = self.pos + while true # sequence + _tmp = apply(:_HtmlBlockOpenBlockquote) + unless _tmp + self.pos = _save + break + end + while true + + _save2 = self.pos + while true # choice + _tmp = apply(:_HtmlBlockBlockquote) + break if _tmp + self.pos = _save2 + + _save3 = self.pos + while true # sequence + _save4 = self.pos + _tmp = apply(:_HtmlBlockCloseBlockquote) + _tmp = _tmp ? nil : true + self.pos = _save4 + unless _tmp + self.pos = _save3 + break + end + _tmp = get_byte + unless _tmp + self.pos = _save3 + end + break + end # end sequence + + break if _tmp + self.pos = _save2 + break + end # end choice + + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_HtmlBlockCloseBlockquote) + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockBlockquote unless _tmp + return _tmp + end + + # HtmlBlockOpenCenter = "<" Spnl ("center" | "CENTER") Spnl HtmlAttribute* ">" + def _HtmlBlockOpenCenter + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("center") + break if _tmp + self.pos = _save1 + _tmp = match_string("CENTER") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + while true + _tmp = apply(:_HtmlAttribute) + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockOpenCenter unless _tmp + return _tmp + end + + # HtmlBlockCloseCenter = "<" Spnl "/" ("center" | "CENTER") Spnl ">" + def _HtmlBlockCloseCenter + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string("/") + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("center") + break if _tmp + self.pos = _save1 + _tmp = match_string("CENTER") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockCloseCenter unless _tmp + return _tmp + end + + # HtmlBlockCenter = HtmlBlockOpenCenter (HtmlBlockCenter | !HtmlBlockCloseCenter .)* HtmlBlockCloseCenter + def _HtmlBlockCenter + + _save = self.pos + while true # sequence + _tmp = apply(:_HtmlBlockOpenCenter) + unless _tmp + self.pos = _save + break + end + while true + + _save2 = self.pos + while true # choice + _tmp = apply(:_HtmlBlockCenter) + break if _tmp + self.pos = _save2 + + _save3 = self.pos + while true # sequence + _save4 = self.pos + _tmp = apply(:_HtmlBlockCloseCenter) + _tmp = _tmp ? nil : true + self.pos = _save4 + unless _tmp + self.pos = _save3 + break + end + _tmp = get_byte + unless _tmp + self.pos = _save3 + end + break + end # end sequence + + break if _tmp + self.pos = _save2 + break + end # end choice + + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_HtmlBlockCloseCenter) + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockCenter unless _tmp + return _tmp + end + + # HtmlBlockOpenDir = "<" Spnl ("dir" | "DIR") Spnl HtmlAttribute* ">" + def _HtmlBlockOpenDir + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("dir") + break if _tmp + self.pos = _save1 + _tmp = match_string("DIR") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + while true + _tmp = apply(:_HtmlAttribute) + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockOpenDir unless _tmp + return _tmp + end + + # HtmlBlockCloseDir = "<" Spnl "/" ("dir" | "DIR") Spnl ">" + def _HtmlBlockCloseDir + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string("/") + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("dir") + break if _tmp + self.pos = _save1 + _tmp = match_string("DIR") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockCloseDir unless _tmp + return _tmp + end + + # HtmlBlockDir = HtmlBlockOpenDir (HtmlBlockDir | !HtmlBlockCloseDir .)* HtmlBlockCloseDir + def _HtmlBlockDir + + _save = self.pos + while true # sequence + _tmp = apply(:_HtmlBlockOpenDir) + unless _tmp + self.pos = _save + break + end + while true + + _save2 = self.pos + while true # choice + _tmp = apply(:_HtmlBlockDir) + break if _tmp + self.pos = _save2 + + _save3 = self.pos + while true # sequence + _save4 = self.pos + _tmp = apply(:_HtmlBlockCloseDir) + _tmp = _tmp ? nil : true + self.pos = _save4 + unless _tmp + self.pos = _save3 + break + end + _tmp = get_byte + unless _tmp + self.pos = _save3 + end + break + end # end sequence + + break if _tmp + self.pos = _save2 + break + end # end choice + + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_HtmlBlockCloseDir) + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockDir unless _tmp + return _tmp + end + + # HtmlBlockOpenDiv = "<" Spnl ("div" | "DIV") Spnl HtmlAttribute* ">" + def _HtmlBlockOpenDiv + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("div") + break if _tmp + self.pos = _save1 + _tmp = match_string("DIV") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + while true + _tmp = apply(:_HtmlAttribute) + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockOpenDiv unless _tmp + return _tmp + end + + # HtmlBlockCloseDiv = "<" Spnl "/" ("div" | "DIV") Spnl ">" + def _HtmlBlockCloseDiv + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string("/") + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("div") + break if _tmp + self.pos = _save1 + _tmp = match_string("DIV") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockCloseDiv unless _tmp + return _tmp + end + + # HtmlBlockDiv = HtmlBlockOpenDiv (HtmlBlockDiv | !HtmlBlockCloseDiv .)* HtmlBlockCloseDiv + def _HtmlBlockDiv + + _save = self.pos + while true # sequence + _tmp = apply(:_HtmlBlockOpenDiv) + unless _tmp + self.pos = _save + break + end + while true + + _save2 = self.pos + while true # choice + _tmp = apply(:_HtmlBlockDiv) + break if _tmp + self.pos = _save2 + + _save3 = self.pos + while true # sequence + _save4 = self.pos + _tmp = apply(:_HtmlBlockCloseDiv) + _tmp = _tmp ? nil : true + self.pos = _save4 + unless _tmp + self.pos = _save3 + break + end + _tmp = get_byte + unless _tmp + self.pos = _save3 + end + break + end # end sequence + + break if _tmp + self.pos = _save2 + break + end # end choice + + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_HtmlBlockCloseDiv) + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockDiv unless _tmp + return _tmp + end + + # HtmlBlockOpenDl = "<" Spnl ("dl" | "DL") Spnl HtmlAttribute* ">" + def _HtmlBlockOpenDl + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("dl") + break if _tmp + self.pos = _save1 + _tmp = match_string("DL") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + while true + _tmp = apply(:_HtmlAttribute) + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockOpenDl unless _tmp + return _tmp + end + + # HtmlBlockCloseDl = "<" Spnl "/" ("dl" | "DL") Spnl ">" + def _HtmlBlockCloseDl + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string("/") + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("dl") + break if _tmp + self.pos = _save1 + _tmp = match_string("DL") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockCloseDl unless _tmp + return _tmp + end + + # HtmlBlockDl = HtmlBlockOpenDl (HtmlBlockDl | !HtmlBlockCloseDl .)* HtmlBlockCloseDl + def _HtmlBlockDl + + _save = self.pos + while true # sequence + _tmp = apply(:_HtmlBlockOpenDl) + unless _tmp + self.pos = _save + break + end + while true + + _save2 = self.pos + while true # choice + _tmp = apply(:_HtmlBlockDl) + break if _tmp + self.pos = _save2 + + _save3 = self.pos + while true # sequence + _save4 = self.pos + _tmp = apply(:_HtmlBlockCloseDl) + _tmp = _tmp ? nil : true + self.pos = _save4 + unless _tmp + self.pos = _save3 + break + end + _tmp = get_byte + unless _tmp + self.pos = _save3 + end + break + end # end sequence + + break if _tmp + self.pos = _save2 + break + end # end choice + + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_HtmlBlockCloseDl) + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockDl unless _tmp + return _tmp + end + + # HtmlBlockOpenFieldset = "<" Spnl ("fieldset" | "FIELDSET") Spnl HtmlAttribute* ">" + def _HtmlBlockOpenFieldset + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("fieldset") + break if _tmp + self.pos = _save1 + _tmp = match_string("FIELDSET") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + while true + _tmp = apply(:_HtmlAttribute) + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockOpenFieldset unless _tmp + return _tmp + end + + # HtmlBlockCloseFieldset = "<" Spnl "/" ("fieldset" | "FIELDSET") Spnl ">" + def _HtmlBlockCloseFieldset + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string("/") + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("fieldset") + break if _tmp + self.pos = _save1 + _tmp = match_string("FIELDSET") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockCloseFieldset unless _tmp + return _tmp + end + + # HtmlBlockFieldset = HtmlBlockOpenFieldset (HtmlBlockFieldset | !HtmlBlockCloseFieldset .)* HtmlBlockCloseFieldset + def _HtmlBlockFieldset + + _save = self.pos + while true # sequence + _tmp = apply(:_HtmlBlockOpenFieldset) + unless _tmp + self.pos = _save + break + end + while true + + _save2 = self.pos + while true # choice + _tmp = apply(:_HtmlBlockFieldset) + break if _tmp + self.pos = _save2 + + _save3 = self.pos + while true # sequence + _save4 = self.pos + _tmp = apply(:_HtmlBlockCloseFieldset) + _tmp = _tmp ? nil : true + self.pos = _save4 + unless _tmp + self.pos = _save3 + break + end + _tmp = get_byte + unless _tmp + self.pos = _save3 + end + break + end # end sequence + + break if _tmp + self.pos = _save2 + break + end # end choice + + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_HtmlBlockCloseFieldset) + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockFieldset unless _tmp + return _tmp + end + + # HtmlBlockOpenForm = "<" Spnl ("form" | "FORM") Spnl HtmlAttribute* ">" + def _HtmlBlockOpenForm + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("form") + break if _tmp + self.pos = _save1 + _tmp = match_string("FORM") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + while true + _tmp = apply(:_HtmlAttribute) + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockOpenForm unless _tmp + return _tmp + end + + # HtmlBlockCloseForm = "<" Spnl "/" ("form" | "FORM") Spnl ">" + def _HtmlBlockCloseForm + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string("/") + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("form") + break if _tmp + self.pos = _save1 + _tmp = match_string("FORM") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockCloseForm unless _tmp + return _tmp + end + + # HtmlBlockForm = HtmlBlockOpenForm (HtmlBlockForm | !HtmlBlockCloseForm .)* HtmlBlockCloseForm + def _HtmlBlockForm + + _save = self.pos + while true # sequence + _tmp = apply(:_HtmlBlockOpenForm) + unless _tmp + self.pos = _save + break + end + while true + + _save2 = self.pos + while true # choice + _tmp = apply(:_HtmlBlockForm) + break if _tmp + self.pos = _save2 + + _save3 = self.pos + while true # sequence + _save4 = self.pos + _tmp = apply(:_HtmlBlockCloseForm) + _tmp = _tmp ? nil : true + self.pos = _save4 + unless _tmp + self.pos = _save3 + break + end + _tmp = get_byte + unless _tmp + self.pos = _save3 + end + break + end # end sequence + + break if _tmp + self.pos = _save2 + break + end # end choice + + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_HtmlBlockCloseForm) + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockForm unless _tmp + return _tmp + end + + # HtmlBlockOpenH1 = "<" Spnl ("h1" | "H1") Spnl HtmlAttribute* ">" + def _HtmlBlockOpenH1 + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("h1") + break if _tmp + self.pos = _save1 + _tmp = match_string("H1") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + while true + _tmp = apply(:_HtmlAttribute) + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockOpenH1 unless _tmp + return _tmp + end + + # HtmlBlockCloseH1 = "<" Spnl "/" ("h1" | "H1") Spnl ">" + def _HtmlBlockCloseH1 + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string("/") + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("h1") + break if _tmp + self.pos = _save1 + _tmp = match_string("H1") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockCloseH1 unless _tmp + return _tmp + end + + # HtmlBlockH1 = HtmlBlockOpenH1 (HtmlBlockH1 | !HtmlBlockCloseH1 .)* HtmlBlockCloseH1 + def _HtmlBlockH1 + + _save = self.pos + while true # sequence + _tmp = apply(:_HtmlBlockOpenH1) + unless _tmp + self.pos = _save + break + end + while true + + _save2 = self.pos + while true # choice + _tmp = apply(:_HtmlBlockH1) + break if _tmp + self.pos = _save2 + + _save3 = self.pos + while true # sequence + _save4 = self.pos + _tmp = apply(:_HtmlBlockCloseH1) + _tmp = _tmp ? nil : true + self.pos = _save4 + unless _tmp + self.pos = _save3 + break + end + _tmp = get_byte + unless _tmp + self.pos = _save3 + end + break + end # end sequence + + break if _tmp + self.pos = _save2 + break + end # end choice + + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_HtmlBlockCloseH1) + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockH1 unless _tmp + return _tmp + end + + # HtmlBlockOpenH2 = "<" Spnl ("h2" | "H2") Spnl HtmlAttribute* ">" + def _HtmlBlockOpenH2 + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("h2") + break if _tmp + self.pos = _save1 + _tmp = match_string("H2") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + while true + _tmp = apply(:_HtmlAttribute) + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockOpenH2 unless _tmp + return _tmp + end + + # HtmlBlockCloseH2 = "<" Spnl "/" ("h2" | "H2") Spnl ">" + def _HtmlBlockCloseH2 + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string("/") + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("h2") + break if _tmp + self.pos = _save1 + _tmp = match_string("H2") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockCloseH2 unless _tmp + return _tmp + end + + # HtmlBlockH2 = HtmlBlockOpenH2 (HtmlBlockH2 | !HtmlBlockCloseH2 .)* HtmlBlockCloseH2 + def _HtmlBlockH2 + + _save = self.pos + while true # sequence + _tmp = apply(:_HtmlBlockOpenH2) + unless _tmp + self.pos = _save + break + end + while true + + _save2 = self.pos + while true # choice + _tmp = apply(:_HtmlBlockH2) + break if _tmp + self.pos = _save2 + + _save3 = self.pos + while true # sequence + _save4 = self.pos + _tmp = apply(:_HtmlBlockCloseH2) + _tmp = _tmp ? nil : true + self.pos = _save4 + unless _tmp + self.pos = _save3 + break + end + _tmp = get_byte + unless _tmp + self.pos = _save3 + end + break + end # end sequence + + break if _tmp + self.pos = _save2 + break + end # end choice + + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_HtmlBlockCloseH2) + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockH2 unless _tmp + return _tmp + end + + # HtmlBlockOpenH3 = "<" Spnl ("h3" | "H3") Spnl HtmlAttribute* ">" + def _HtmlBlockOpenH3 + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("h3") + break if _tmp + self.pos = _save1 + _tmp = match_string("H3") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + while true + _tmp = apply(:_HtmlAttribute) + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockOpenH3 unless _tmp + return _tmp + end + + # HtmlBlockCloseH3 = "<" Spnl "/" ("h3" | "H3") Spnl ">" + def _HtmlBlockCloseH3 + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string("/") + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("h3") + break if _tmp + self.pos = _save1 + _tmp = match_string("H3") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockCloseH3 unless _tmp + return _tmp + end + + # HtmlBlockH3 = HtmlBlockOpenH3 (HtmlBlockH3 | !HtmlBlockCloseH3 .)* HtmlBlockCloseH3 + def _HtmlBlockH3 + + _save = self.pos + while true # sequence + _tmp = apply(:_HtmlBlockOpenH3) + unless _tmp + self.pos = _save + break + end + while true + + _save2 = self.pos + while true # choice + _tmp = apply(:_HtmlBlockH3) + break if _tmp + self.pos = _save2 + + _save3 = self.pos + while true # sequence + _save4 = self.pos + _tmp = apply(:_HtmlBlockCloseH3) + _tmp = _tmp ? nil : true + self.pos = _save4 + unless _tmp + self.pos = _save3 + break + end + _tmp = get_byte + unless _tmp + self.pos = _save3 + end + break + end # end sequence + + break if _tmp + self.pos = _save2 + break + end # end choice + + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_HtmlBlockCloseH3) + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockH3 unless _tmp + return _tmp + end + + # HtmlBlockOpenH4 = "<" Spnl ("h4" | "H4") Spnl HtmlAttribute* ">" + def _HtmlBlockOpenH4 + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("h4") + break if _tmp + self.pos = _save1 + _tmp = match_string("H4") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + while true + _tmp = apply(:_HtmlAttribute) + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockOpenH4 unless _tmp + return _tmp + end + + # HtmlBlockCloseH4 = "<" Spnl "/" ("h4" | "H4") Spnl ">" + def _HtmlBlockCloseH4 + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string("/") + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("h4") + break if _tmp + self.pos = _save1 + _tmp = match_string("H4") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockCloseH4 unless _tmp + return _tmp + end + + # HtmlBlockH4 = HtmlBlockOpenH4 (HtmlBlockH4 | !HtmlBlockCloseH4 .)* HtmlBlockCloseH4 + def _HtmlBlockH4 + + _save = self.pos + while true # sequence + _tmp = apply(:_HtmlBlockOpenH4) + unless _tmp + self.pos = _save + break + end + while true + + _save2 = self.pos + while true # choice + _tmp = apply(:_HtmlBlockH4) + break if _tmp + self.pos = _save2 + + _save3 = self.pos + while true # sequence + _save4 = self.pos + _tmp = apply(:_HtmlBlockCloseH4) + _tmp = _tmp ? nil : true + self.pos = _save4 + unless _tmp + self.pos = _save3 + break + end + _tmp = get_byte + unless _tmp + self.pos = _save3 + end + break + end # end sequence + + break if _tmp + self.pos = _save2 + break + end # end choice + + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_HtmlBlockCloseH4) + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockH4 unless _tmp + return _tmp + end + + # HtmlBlockOpenH5 = "<" Spnl ("h5" | "H5") Spnl HtmlAttribute* ">" + def _HtmlBlockOpenH5 + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("h5") + break if _tmp + self.pos = _save1 + _tmp = match_string("H5") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + while true + _tmp = apply(:_HtmlAttribute) + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockOpenH5 unless _tmp + return _tmp + end + + # HtmlBlockCloseH5 = "<" Spnl "/" ("h5" | "H5") Spnl ">" + def _HtmlBlockCloseH5 + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string("/") + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("h5") + break if _tmp + self.pos = _save1 + _tmp = match_string("H5") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockCloseH5 unless _tmp + return _tmp + end + + # HtmlBlockH5 = HtmlBlockOpenH5 (HtmlBlockH5 | !HtmlBlockCloseH5 .)* HtmlBlockCloseH5 + def _HtmlBlockH5 + + _save = self.pos + while true # sequence + _tmp = apply(:_HtmlBlockOpenH5) + unless _tmp + self.pos = _save + break + end + while true + + _save2 = self.pos + while true # choice + _tmp = apply(:_HtmlBlockH5) + break if _tmp + self.pos = _save2 + + _save3 = self.pos + while true # sequence + _save4 = self.pos + _tmp = apply(:_HtmlBlockCloseH5) + _tmp = _tmp ? nil : true + self.pos = _save4 + unless _tmp + self.pos = _save3 + break + end + _tmp = get_byte + unless _tmp + self.pos = _save3 + end + break + end # end sequence + + break if _tmp + self.pos = _save2 + break + end # end choice + + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_HtmlBlockCloseH5) + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockH5 unless _tmp + return _tmp + end + + # HtmlBlockOpenH6 = "<" Spnl ("h6" | "H6") Spnl HtmlAttribute* ">" + def _HtmlBlockOpenH6 + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("h6") + break if _tmp + self.pos = _save1 + _tmp = match_string("H6") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + while true + _tmp = apply(:_HtmlAttribute) + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockOpenH6 unless _tmp + return _tmp + end + + # HtmlBlockCloseH6 = "<" Spnl "/" ("h6" | "H6") Spnl ">" + def _HtmlBlockCloseH6 + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string("/") + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("h6") + break if _tmp + self.pos = _save1 + _tmp = match_string("H6") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockCloseH6 unless _tmp + return _tmp + end + + # HtmlBlockH6 = HtmlBlockOpenH6 (HtmlBlockH6 | !HtmlBlockCloseH6 .)* HtmlBlockCloseH6 + def _HtmlBlockH6 + + _save = self.pos + while true # sequence + _tmp = apply(:_HtmlBlockOpenH6) + unless _tmp + self.pos = _save + break + end + while true + + _save2 = self.pos + while true # choice + _tmp = apply(:_HtmlBlockH6) + break if _tmp + self.pos = _save2 + + _save3 = self.pos + while true # sequence + _save4 = self.pos + _tmp = apply(:_HtmlBlockCloseH6) + _tmp = _tmp ? nil : true + self.pos = _save4 + unless _tmp + self.pos = _save3 + break + end + _tmp = get_byte + unless _tmp + self.pos = _save3 + end + break + end # end sequence + + break if _tmp + self.pos = _save2 + break + end # end choice + + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_HtmlBlockCloseH6) + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockH6 unless _tmp + return _tmp + end + + # HtmlBlockOpenMenu = "<" Spnl ("menu" | "MENU") Spnl HtmlAttribute* ">" + def _HtmlBlockOpenMenu + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("menu") + break if _tmp + self.pos = _save1 + _tmp = match_string("MENU") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + while true + _tmp = apply(:_HtmlAttribute) + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockOpenMenu unless _tmp + return _tmp + end + + # HtmlBlockCloseMenu = "<" Spnl "/" ("menu" | "MENU") Spnl ">" + def _HtmlBlockCloseMenu + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string("/") + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("menu") + break if _tmp + self.pos = _save1 + _tmp = match_string("MENU") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockCloseMenu unless _tmp + return _tmp + end + + # HtmlBlockMenu = HtmlBlockOpenMenu (HtmlBlockMenu | !HtmlBlockCloseMenu .)* HtmlBlockCloseMenu + def _HtmlBlockMenu + + _save = self.pos + while true # sequence + _tmp = apply(:_HtmlBlockOpenMenu) + unless _tmp + self.pos = _save + break + end + while true + + _save2 = self.pos + while true # choice + _tmp = apply(:_HtmlBlockMenu) + break if _tmp + self.pos = _save2 + + _save3 = self.pos + while true # sequence + _save4 = self.pos + _tmp = apply(:_HtmlBlockCloseMenu) + _tmp = _tmp ? nil : true + self.pos = _save4 + unless _tmp + self.pos = _save3 + break + end + _tmp = get_byte + unless _tmp + self.pos = _save3 + end + break + end # end sequence + + break if _tmp + self.pos = _save2 + break + end # end choice + + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_HtmlBlockCloseMenu) + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockMenu unless _tmp + return _tmp + end + + # HtmlBlockOpenNoframes = "<" Spnl ("noframes" | "NOFRAMES") Spnl HtmlAttribute* ">" + def _HtmlBlockOpenNoframes + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("noframes") + break if _tmp + self.pos = _save1 + _tmp = match_string("NOFRAMES") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + while true + _tmp = apply(:_HtmlAttribute) + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockOpenNoframes unless _tmp + return _tmp + end + + # HtmlBlockCloseNoframes = "<" Spnl "/" ("noframes" | "NOFRAMES") Spnl ">" + def _HtmlBlockCloseNoframes + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string("/") + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("noframes") + break if _tmp + self.pos = _save1 + _tmp = match_string("NOFRAMES") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockCloseNoframes unless _tmp + return _tmp + end + + # HtmlBlockNoframes = HtmlBlockOpenNoframes (HtmlBlockNoframes | !HtmlBlockCloseNoframes .)* HtmlBlockCloseNoframes + def _HtmlBlockNoframes + + _save = self.pos + while true # sequence + _tmp = apply(:_HtmlBlockOpenNoframes) + unless _tmp + self.pos = _save + break + end + while true + + _save2 = self.pos + while true # choice + _tmp = apply(:_HtmlBlockNoframes) + break if _tmp + self.pos = _save2 + + _save3 = self.pos + while true # sequence + _save4 = self.pos + _tmp = apply(:_HtmlBlockCloseNoframes) + _tmp = _tmp ? nil : true + self.pos = _save4 + unless _tmp + self.pos = _save3 + break + end + _tmp = get_byte + unless _tmp + self.pos = _save3 + end + break + end # end sequence + + break if _tmp + self.pos = _save2 + break + end # end choice + + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_HtmlBlockCloseNoframes) + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockNoframes unless _tmp + return _tmp + end + + # HtmlBlockOpenNoscript = "<" Spnl ("noscript" | "NOSCRIPT") Spnl HtmlAttribute* ">" + def _HtmlBlockOpenNoscript + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("noscript") + break if _tmp + self.pos = _save1 + _tmp = match_string("NOSCRIPT") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + while true + _tmp = apply(:_HtmlAttribute) + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockOpenNoscript unless _tmp + return _tmp + end + + # HtmlBlockCloseNoscript = "<" Spnl "/" ("noscript" | "NOSCRIPT") Spnl ">" + def _HtmlBlockCloseNoscript + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string("/") + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("noscript") + break if _tmp + self.pos = _save1 + _tmp = match_string("NOSCRIPT") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockCloseNoscript unless _tmp + return _tmp + end + + # HtmlBlockNoscript = HtmlBlockOpenNoscript (HtmlBlockNoscript | !HtmlBlockCloseNoscript .)* HtmlBlockCloseNoscript + def _HtmlBlockNoscript + + _save = self.pos + while true # sequence + _tmp = apply(:_HtmlBlockOpenNoscript) + unless _tmp + self.pos = _save + break + end + while true + + _save2 = self.pos + while true # choice + _tmp = apply(:_HtmlBlockNoscript) + break if _tmp + self.pos = _save2 + + _save3 = self.pos + while true # sequence + _save4 = self.pos + _tmp = apply(:_HtmlBlockCloseNoscript) + _tmp = _tmp ? nil : true + self.pos = _save4 + unless _tmp + self.pos = _save3 + break + end + _tmp = get_byte + unless _tmp + self.pos = _save3 + end + break + end # end sequence + + break if _tmp + self.pos = _save2 + break + end # end choice + + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_HtmlBlockCloseNoscript) + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockNoscript unless _tmp + return _tmp + end + + # HtmlBlockOpenOl = "<" Spnl ("ol" | "OL") Spnl HtmlAttribute* ">" + def _HtmlBlockOpenOl + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("ol") + break if _tmp + self.pos = _save1 + _tmp = match_string("OL") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + while true + _tmp = apply(:_HtmlAttribute) + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockOpenOl unless _tmp + return _tmp + end + + # HtmlBlockCloseOl = "<" Spnl "/" ("ol" | "OL") Spnl ">" + def _HtmlBlockCloseOl + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string("/") + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("ol") + break if _tmp + self.pos = _save1 + _tmp = match_string("OL") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockCloseOl unless _tmp + return _tmp + end + + # HtmlBlockOl = HtmlBlockOpenOl (HtmlBlockOl | !HtmlBlockCloseOl .)* HtmlBlockCloseOl + def _HtmlBlockOl + + _save = self.pos + while true # sequence + _tmp = apply(:_HtmlBlockOpenOl) + unless _tmp + self.pos = _save + break + end + while true + + _save2 = self.pos + while true # choice + _tmp = apply(:_HtmlBlockOl) + break if _tmp + self.pos = _save2 + + _save3 = self.pos + while true # sequence + _save4 = self.pos + _tmp = apply(:_HtmlBlockCloseOl) + _tmp = _tmp ? nil : true + self.pos = _save4 + unless _tmp + self.pos = _save3 + break + end + _tmp = get_byte + unless _tmp + self.pos = _save3 + end + break + end # end sequence + + break if _tmp + self.pos = _save2 + break + end # end choice + + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_HtmlBlockCloseOl) + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockOl unless _tmp + return _tmp + end + + # HtmlBlockOpenP = "<" Spnl ("p" | "P") Spnl HtmlAttribute* ">" + def _HtmlBlockOpenP + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("p") + break if _tmp + self.pos = _save1 + _tmp = match_string("P") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + while true + _tmp = apply(:_HtmlAttribute) + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockOpenP unless _tmp + return _tmp + end + + # HtmlBlockCloseP = "<" Spnl "/" ("p" | "P") Spnl ">" + def _HtmlBlockCloseP + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string("/") + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("p") + break if _tmp + self.pos = _save1 + _tmp = match_string("P") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockCloseP unless _tmp + return _tmp + end + + # HtmlBlockP = HtmlBlockOpenP (HtmlBlockP | !HtmlBlockCloseP .)* HtmlBlockCloseP + def _HtmlBlockP + + _save = self.pos + while true # sequence + _tmp = apply(:_HtmlBlockOpenP) + unless _tmp + self.pos = _save + break + end + while true + + _save2 = self.pos + while true # choice + _tmp = apply(:_HtmlBlockP) + break if _tmp + self.pos = _save2 + + _save3 = self.pos + while true # sequence + _save4 = self.pos + _tmp = apply(:_HtmlBlockCloseP) + _tmp = _tmp ? nil : true + self.pos = _save4 + unless _tmp + self.pos = _save3 + break + end + _tmp = get_byte + unless _tmp + self.pos = _save3 + end + break + end # end sequence + + break if _tmp + self.pos = _save2 + break + end # end choice + + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_HtmlBlockCloseP) + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockP unless _tmp + return _tmp + end + + # HtmlBlockOpenPre = "<" Spnl ("pre" | "PRE") Spnl HtmlAttribute* ">" + def _HtmlBlockOpenPre + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("pre") + break if _tmp + self.pos = _save1 + _tmp = match_string("PRE") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + while true + _tmp = apply(:_HtmlAttribute) + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockOpenPre unless _tmp + return _tmp + end + + # HtmlBlockClosePre = "<" Spnl "/" ("pre" | "PRE") Spnl ">" + def _HtmlBlockClosePre + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string("/") + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("pre") + break if _tmp + self.pos = _save1 + _tmp = match_string("PRE") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockClosePre unless _tmp + return _tmp + end + + # HtmlBlockPre = HtmlBlockOpenPre (HtmlBlockPre | !HtmlBlockClosePre .)* HtmlBlockClosePre + def _HtmlBlockPre + + _save = self.pos + while true # sequence + _tmp = apply(:_HtmlBlockOpenPre) + unless _tmp + self.pos = _save + break + end + while true + + _save2 = self.pos + while true # choice + _tmp = apply(:_HtmlBlockPre) + break if _tmp + self.pos = _save2 + + _save3 = self.pos + while true # sequence + _save4 = self.pos + _tmp = apply(:_HtmlBlockClosePre) + _tmp = _tmp ? nil : true + self.pos = _save4 + unless _tmp + self.pos = _save3 + break + end + _tmp = get_byte + unless _tmp + self.pos = _save3 + end + break + end # end sequence + + break if _tmp + self.pos = _save2 + break + end # end choice + + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_HtmlBlockClosePre) + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockPre unless _tmp + return _tmp + end + + # HtmlBlockOpenTable = "<" Spnl ("table" | "TABLE") Spnl HtmlAttribute* ">" + def _HtmlBlockOpenTable + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("table") + break if _tmp + self.pos = _save1 + _tmp = match_string("TABLE") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + while true + _tmp = apply(:_HtmlAttribute) + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockOpenTable unless _tmp + return _tmp + end + + # HtmlBlockCloseTable = "<" Spnl "/" ("table" | "TABLE") Spnl ">" + def _HtmlBlockCloseTable + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string("/") + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("table") + break if _tmp + self.pos = _save1 + _tmp = match_string("TABLE") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockCloseTable unless _tmp + return _tmp + end + + # HtmlBlockTable = HtmlBlockOpenTable (HtmlBlockTable | !HtmlBlockCloseTable .)* HtmlBlockCloseTable + def _HtmlBlockTable + + _save = self.pos + while true # sequence + _tmp = apply(:_HtmlBlockOpenTable) + unless _tmp + self.pos = _save + break + end + while true + + _save2 = self.pos + while true # choice + _tmp = apply(:_HtmlBlockTable) + break if _tmp + self.pos = _save2 + + _save3 = self.pos + while true # sequence + _save4 = self.pos + _tmp = apply(:_HtmlBlockCloseTable) + _tmp = _tmp ? nil : true + self.pos = _save4 + unless _tmp + self.pos = _save3 + break + end + _tmp = get_byte + unless _tmp + self.pos = _save3 + end + break + end # end sequence + + break if _tmp + self.pos = _save2 + break + end # end choice + + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_HtmlBlockCloseTable) + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockTable unless _tmp + return _tmp + end + + # HtmlBlockOpenUl = "<" Spnl ("ul" | "UL") Spnl HtmlAttribute* ">" + def _HtmlBlockOpenUl + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("ul") + break if _tmp + self.pos = _save1 + _tmp = match_string("UL") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + while true + _tmp = apply(:_HtmlAttribute) + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockOpenUl unless _tmp + return _tmp + end + + # HtmlBlockCloseUl = "<" Spnl "/" ("ul" | "UL") Spnl ">" + def _HtmlBlockCloseUl + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string("/") + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("ul") + break if _tmp + self.pos = _save1 + _tmp = match_string("UL") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockCloseUl unless _tmp + return _tmp + end + + # HtmlBlockUl = HtmlBlockOpenUl (HtmlBlockUl | !HtmlBlockCloseUl .)* HtmlBlockCloseUl + def _HtmlBlockUl + + _save = self.pos + while true # sequence + _tmp = apply(:_HtmlBlockOpenUl) + unless _tmp + self.pos = _save + break + end + while true + + _save2 = self.pos + while true # choice + _tmp = apply(:_HtmlBlockUl) + break if _tmp + self.pos = _save2 + + _save3 = self.pos + while true # sequence + _save4 = self.pos + _tmp = apply(:_HtmlBlockCloseUl) + _tmp = _tmp ? nil : true + self.pos = _save4 + unless _tmp + self.pos = _save3 + break + end + _tmp = get_byte + unless _tmp + self.pos = _save3 + end + break + end # end sequence + + break if _tmp + self.pos = _save2 + break + end # end choice + + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_HtmlBlockCloseUl) + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockUl unless _tmp + return _tmp + end + + # HtmlBlockOpenDd = "<" Spnl ("dd" | "DD") Spnl HtmlAttribute* ">" + def _HtmlBlockOpenDd + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("dd") + break if _tmp + self.pos = _save1 + _tmp = match_string("DD") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + while true + _tmp = apply(:_HtmlAttribute) + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockOpenDd unless _tmp + return _tmp + end + + # HtmlBlockCloseDd = "<" Spnl "/" ("dd" | "DD") Spnl ">" + def _HtmlBlockCloseDd + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string("/") + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("dd") + break if _tmp + self.pos = _save1 + _tmp = match_string("DD") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockCloseDd unless _tmp + return _tmp + end + + # HtmlBlockDd = HtmlBlockOpenDd (HtmlBlockDd | !HtmlBlockCloseDd .)* HtmlBlockCloseDd + def _HtmlBlockDd + + _save = self.pos + while true # sequence + _tmp = apply(:_HtmlBlockOpenDd) + unless _tmp + self.pos = _save + break + end + while true + + _save2 = self.pos + while true # choice + _tmp = apply(:_HtmlBlockDd) + break if _tmp + self.pos = _save2 + + _save3 = self.pos + while true # sequence + _save4 = self.pos + _tmp = apply(:_HtmlBlockCloseDd) + _tmp = _tmp ? nil : true + self.pos = _save4 + unless _tmp + self.pos = _save3 + break + end + _tmp = get_byte + unless _tmp + self.pos = _save3 + end + break + end # end sequence + + break if _tmp + self.pos = _save2 + break + end # end choice + + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_HtmlBlockCloseDd) + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockDd unless _tmp + return _tmp + end + + # HtmlBlockOpenDt = "<" Spnl ("dt" | "DT") Spnl HtmlAttribute* ">" + def _HtmlBlockOpenDt + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("dt") + break if _tmp + self.pos = _save1 + _tmp = match_string("DT") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + while true + _tmp = apply(:_HtmlAttribute) + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockOpenDt unless _tmp + return _tmp + end + + # HtmlBlockCloseDt = "<" Spnl "/" ("dt" | "DT") Spnl ">" + def _HtmlBlockCloseDt + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string("/") + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("dt") + break if _tmp + self.pos = _save1 + _tmp = match_string("DT") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockCloseDt unless _tmp + return _tmp + end + + # HtmlBlockDt = HtmlBlockOpenDt (HtmlBlockDt | !HtmlBlockCloseDt .)* HtmlBlockCloseDt + def _HtmlBlockDt + + _save = self.pos + while true # sequence + _tmp = apply(:_HtmlBlockOpenDt) + unless _tmp + self.pos = _save + break + end + while true + + _save2 = self.pos + while true # choice + _tmp = apply(:_HtmlBlockDt) + break if _tmp + self.pos = _save2 + + _save3 = self.pos + while true # sequence + _save4 = self.pos + _tmp = apply(:_HtmlBlockCloseDt) + _tmp = _tmp ? nil : true + self.pos = _save4 + unless _tmp + self.pos = _save3 + break + end + _tmp = get_byte + unless _tmp + self.pos = _save3 + end + break + end # end sequence + + break if _tmp + self.pos = _save2 + break + end # end choice + + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_HtmlBlockCloseDt) + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockDt unless _tmp + return _tmp + end + + # HtmlBlockOpenFrameset = "<" Spnl ("frameset" | "FRAMESET") Spnl HtmlAttribute* ">" + def _HtmlBlockOpenFrameset + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("frameset") + break if _tmp + self.pos = _save1 + _tmp = match_string("FRAMESET") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + while true + _tmp = apply(:_HtmlAttribute) + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockOpenFrameset unless _tmp + return _tmp + end + + # HtmlBlockCloseFrameset = "<" Spnl "/" ("frameset" | "FRAMESET") Spnl ">" + def _HtmlBlockCloseFrameset + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string("/") + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("frameset") + break if _tmp + self.pos = _save1 + _tmp = match_string("FRAMESET") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockCloseFrameset unless _tmp + return _tmp + end + + # HtmlBlockFrameset = HtmlBlockOpenFrameset (HtmlBlockFrameset | !HtmlBlockCloseFrameset .)* HtmlBlockCloseFrameset + def _HtmlBlockFrameset + + _save = self.pos + while true # sequence + _tmp = apply(:_HtmlBlockOpenFrameset) + unless _tmp + self.pos = _save + break + end + while true + + _save2 = self.pos + while true # choice + _tmp = apply(:_HtmlBlockFrameset) + break if _tmp + self.pos = _save2 + + _save3 = self.pos + while true # sequence + _save4 = self.pos + _tmp = apply(:_HtmlBlockCloseFrameset) + _tmp = _tmp ? nil : true + self.pos = _save4 + unless _tmp + self.pos = _save3 + break + end + _tmp = get_byte + unless _tmp + self.pos = _save3 + end + break + end # end sequence + + break if _tmp + self.pos = _save2 + break + end # end choice + + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_HtmlBlockCloseFrameset) + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockFrameset unless _tmp + return _tmp + end + + # HtmlBlockOpenLi = "<" Spnl ("li" | "LI") Spnl HtmlAttribute* ">" + def _HtmlBlockOpenLi + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("li") + break if _tmp + self.pos = _save1 + _tmp = match_string("LI") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + while true + _tmp = apply(:_HtmlAttribute) + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockOpenLi unless _tmp + return _tmp + end + + # HtmlBlockCloseLi = "<" Spnl "/" ("li" | "LI") Spnl ">" + def _HtmlBlockCloseLi + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string("/") + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("li") + break if _tmp + self.pos = _save1 + _tmp = match_string("LI") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockCloseLi unless _tmp + return _tmp + end + + # HtmlBlockLi = HtmlBlockOpenLi (HtmlBlockLi | !HtmlBlockCloseLi .)* HtmlBlockCloseLi + def _HtmlBlockLi + + _save = self.pos + while true # sequence + _tmp = apply(:_HtmlBlockOpenLi) + unless _tmp + self.pos = _save + break + end + while true + + _save2 = self.pos + while true # choice + _tmp = apply(:_HtmlBlockLi) + break if _tmp + self.pos = _save2 + + _save3 = self.pos + while true # sequence + _save4 = self.pos + _tmp = apply(:_HtmlBlockCloseLi) + _tmp = _tmp ? nil : true + self.pos = _save4 + unless _tmp + self.pos = _save3 + break + end + _tmp = get_byte + unless _tmp + self.pos = _save3 + end + break + end # end sequence + + break if _tmp + self.pos = _save2 + break + end # end choice + + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_HtmlBlockCloseLi) + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockLi unless _tmp + return _tmp + end + + # HtmlBlockOpenTbody = "<" Spnl ("tbody" | "TBODY") Spnl HtmlAttribute* ">" + def _HtmlBlockOpenTbody + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("tbody") + break if _tmp + self.pos = _save1 + _tmp = match_string("TBODY") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + while true + _tmp = apply(:_HtmlAttribute) + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockOpenTbody unless _tmp + return _tmp + end + + # HtmlBlockCloseTbody = "<" Spnl "/" ("tbody" | "TBODY") Spnl ">" + def _HtmlBlockCloseTbody + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string("/") + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("tbody") + break if _tmp + self.pos = _save1 + _tmp = match_string("TBODY") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockCloseTbody unless _tmp + return _tmp + end + + # HtmlBlockTbody = HtmlBlockOpenTbody (HtmlBlockTbody | !HtmlBlockCloseTbody .)* HtmlBlockCloseTbody + def _HtmlBlockTbody + + _save = self.pos + while true # sequence + _tmp = apply(:_HtmlBlockOpenTbody) + unless _tmp + self.pos = _save + break + end + while true + + _save2 = self.pos + while true # choice + _tmp = apply(:_HtmlBlockTbody) + break if _tmp + self.pos = _save2 + + _save3 = self.pos + while true # sequence + _save4 = self.pos + _tmp = apply(:_HtmlBlockCloseTbody) + _tmp = _tmp ? nil : true + self.pos = _save4 + unless _tmp + self.pos = _save3 + break + end + _tmp = get_byte + unless _tmp + self.pos = _save3 + end + break + end # end sequence + + break if _tmp + self.pos = _save2 + break + end # end choice + + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_HtmlBlockCloseTbody) + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockTbody unless _tmp + return _tmp + end + + # HtmlBlockOpenTd = "<" Spnl ("td" | "TD") Spnl HtmlAttribute* ">" + def _HtmlBlockOpenTd + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("td") + break if _tmp + self.pos = _save1 + _tmp = match_string("TD") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + while true + _tmp = apply(:_HtmlAttribute) + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockOpenTd unless _tmp + return _tmp + end + + # HtmlBlockCloseTd = "<" Spnl "/" ("td" | "TD") Spnl ">" + def _HtmlBlockCloseTd + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string("/") + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("td") + break if _tmp + self.pos = _save1 + _tmp = match_string("TD") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockCloseTd unless _tmp + return _tmp + end + + # HtmlBlockTd = HtmlBlockOpenTd (HtmlBlockTd | !HtmlBlockCloseTd .)* HtmlBlockCloseTd + def _HtmlBlockTd + + _save = self.pos + while true # sequence + _tmp = apply(:_HtmlBlockOpenTd) + unless _tmp + self.pos = _save + break + end + while true + + _save2 = self.pos + while true # choice + _tmp = apply(:_HtmlBlockTd) + break if _tmp + self.pos = _save2 + + _save3 = self.pos + while true # sequence + _save4 = self.pos + _tmp = apply(:_HtmlBlockCloseTd) + _tmp = _tmp ? nil : true + self.pos = _save4 + unless _tmp + self.pos = _save3 + break + end + _tmp = get_byte + unless _tmp + self.pos = _save3 + end + break + end # end sequence + + break if _tmp + self.pos = _save2 + break + end # end choice + + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_HtmlBlockCloseTd) + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockTd unless _tmp + return _tmp + end + + # HtmlBlockOpenTfoot = "<" Spnl ("tfoot" | "TFOOT") Spnl HtmlAttribute* ">" + def _HtmlBlockOpenTfoot + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("tfoot") + break if _tmp + self.pos = _save1 + _tmp = match_string("TFOOT") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + while true + _tmp = apply(:_HtmlAttribute) + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockOpenTfoot unless _tmp + return _tmp + end + + # HtmlBlockCloseTfoot = "<" Spnl "/" ("tfoot" | "TFOOT") Spnl ">" + def _HtmlBlockCloseTfoot + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string("/") + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("tfoot") + break if _tmp + self.pos = _save1 + _tmp = match_string("TFOOT") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockCloseTfoot unless _tmp + return _tmp + end + + # HtmlBlockTfoot = HtmlBlockOpenTfoot (HtmlBlockTfoot | !HtmlBlockCloseTfoot .)* HtmlBlockCloseTfoot + def _HtmlBlockTfoot + + _save = self.pos + while true # sequence + _tmp = apply(:_HtmlBlockOpenTfoot) + unless _tmp + self.pos = _save + break + end + while true + + _save2 = self.pos + while true # choice + _tmp = apply(:_HtmlBlockTfoot) + break if _tmp + self.pos = _save2 + + _save3 = self.pos + while true # sequence + _save4 = self.pos + _tmp = apply(:_HtmlBlockCloseTfoot) + _tmp = _tmp ? nil : true + self.pos = _save4 + unless _tmp + self.pos = _save3 + break + end + _tmp = get_byte + unless _tmp + self.pos = _save3 + end + break + end # end sequence + + break if _tmp + self.pos = _save2 + break + end # end choice + + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_HtmlBlockCloseTfoot) + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockTfoot unless _tmp + return _tmp + end + + # HtmlBlockOpenTh = "<" Spnl ("th" | "TH") Spnl HtmlAttribute* ">" + def _HtmlBlockOpenTh + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("th") + break if _tmp + self.pos = _save1 + _tmp = match_string("TH") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + while true + _tmp = apply(:_HtmlAttribute) + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockOpenTh unless _tmp + return _tmp + end + + # HtmlBlockCloseTh = "<" Spnl "/" ("th" | "TH") Spnl ">" + def _HtmlBlockCloseTh + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string("/") + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("th") + break if _tmp + self.pos = _save1 + _tmp = match_string("TH") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockCloseTh unless _tmp + return _tmp + end + + # HtmlBlockTh = HtmlBlockOpenTh (HtmlBlockTh | !HtmlBlockCloseTh .)* HtmlBlockCloseTh + def _HtmlBlockTh + + _save = self.pos + while true # sequence + _tmp = apply(:_HtmlBlockOpenTh) + unless _tmp + self.pos = _save + break + end + while true + + _save2 = self.pos + while true # choice + _tmp = apply(:_HtmlBlockTh) + break if _tmp + self.pos = _save2 + + _save3 = self.pos + while true # sequence + _save4 = self.pos + _tmp = apply(:_HtmlBlockCloseTh) + _tmp = _tmp ? nil : true + self.pos = _save4 + unless _tmp + self.pos = _save3 + break + end + _tmp = get_byte + unless _tmp + self.pos = _save3 + end + break + end # end sequence + + break if _tmp + self.pos = _save2 + break + end # end choice + + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_HtmlBlockCloseTh) + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockTh unless _tmp + return _tmp + end + + # HtmlBlockOpenThead = "<" Spnl ("thead" | "THEAD") Spnl HtmlAttribute* ">" + def _HtmlBlockOpenThead + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("thead") + break if _tmp + self.pos = _save1 + _tmp = match_string("THEAD") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + while true + _tmp = apply(:_HtmlAttribute) + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockOpenThead unless _tmp + return _tmp + end + + # HtmlBlockCloseThead = "<" Spnl "/" ("thead" | "THEAD") Spnl ">" + def _HtmlBlockCloseThead + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string("/") + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("thead") + break if _tmp + self.pos = _save1 + _tmp = match_string("THEAD") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockCloseThead unless _tmp + return _tmp + end + + # HtmlBlockThead = HtmlBlockOpenThead (HtmlBlockThead | !HtmlBlockCloseThead .)* HtmlBlockCloseThead + def _HtmlBlockThead + + _save = self.pos + while true # sequence + _tmp = apply(:_HtmlBlockOpenThead) + unless _tmp + self.pos = _save + break + end + while true + + _save2 = self.pos + while true # choice + _tmp = apply(:_HtmlBlockThead) + break if _tmp + self.pos = _save2 + + _save3 = self.pos + while true # sequence + _save4 = self.pos + _tmp = apply(:_HtmlBlockCloseThead) + _tmp = _tmp ? nil : true + self.pos = _save4 + unless _tmp + self.pos = _save3 + break + end + _tmp = get_byte + unless _tmp + self.pos = _save3 + end + break + end # end sequence + + break if _tmp + self.pos = _save2 + break + end # end choice + + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_HtmlBlockCloseThead) + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockThead unless _tmp + return _tmp + end + + # HtmlBlockOpenTr = "<" Spnl ("tr" | "TR") Spnl HtmlAttribute* ">" + def _HtmlBlockOpenTr + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("tr") + break if _tmp + self.pos = _save1 + _tmp = match_string("TR") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + while true + _tmp = apply(:_HtmlAttribute) + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockOpenTr unless _tmp + return _tmp + end + + # HtmlBlockCloseTr = "<" Spnl "/" ("tr" | "TR") Spnl ">" + def _HtmlBlockCloseTr + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string("/") + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("tr") + break if _tmp + self.pos = _save1 + _tmp = match_string("TR") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockCloseTr unless _tmp + return _tmp + end + + # HtmlBlockTr = HtmlBlockOpenTr (HtmlBlockTr | !HtmlBlockCloseTr .)* HtmlBlockCloseTr + def _HtmlBlockTr + + _save = self.pos + while true # sequence + _tmp = apply(:_HtmlBlockOpenTr) + unless _tmp + self.pos = _save + break + end + while true + + _save2 = self.pos + while true # choice + _tmp = apply(:_HtmlBlockTr) + break if _tmp + self.pos = _save2 + + _save3 = self.pos + while true # sequence + _save4 = self.pos + _tmp = apply(:_HtmlBlockCloseTr) + _tmp = _tmp ? nil : true + self.pos = _save4 + unless _tmp + self.pos = _save3 + break + end + _tmp = get_byte + unless _tmp + self.pos = _save3 + end + break + end # end sequence + + break if _tmp + self.pos = _save2 + break + end # end choice + + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_HtmlBlockCloseTr) + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockTr unless _tmp + return _tmp + end + + # HtmlBlockOpenScript = "<" Spnl ("script" | "SCRIPT") Spnl HtmlAttribute* ">" + def _HtmlBlockOpenScript + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("script") + break if _tmp + self.pos = _save1 + _tmp = match_string("SCRIPT") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + while true + _tmp = apply(:_HtmlAttribute) + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockOpenScript unless _tmp + return _tmp + end + + # HtmlBlockCloseScript = "<" Spnl "/" ("script" | "SCRIPT") Spnl ">" + def _HtmlBlockCloseScript + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string("/") + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("script") + break if _tmp + self.pos = _save1 + _tmp = match_string("SCRIPT") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockCloseScript unless _tmp + return _tmp + end + + # HtmlBlockScript = HtmlBlockOpenScript (!HtmlBlockCloseScript .)* HtmlBlockCloseScript + def _HtmlBlockScript + + _save = self.pos + while true # sequence + _tmp = apply(:_HtmlBlockOpenScript) + unless _tmp + self.pos = _save + break + end + while true + + _save2 = self.pos + while true # sequence + _save3 = self.pos + _tmp = apply(:_HtmlBlockCloseScript) + _tmp = _tmp ? nil : true + self.pos = _save3 + unless _tmp + self.pos = _save2 + break + end + _tmp = get_byte + unless _tmp + self.pos = _save2 + end + break + end # end sequence + + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_HtmlBlockCloseScript) + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockScript unless _tmp + return _tmp + end + + # HtmlBlockInTags = (HtmlAnchor | HtmlBlockAddress | HtmlBlockBlockquote | HtmlBlockCenter | HtmlBlockDir | HtmlBlockDiv | HtmlBlockDl | HtmlBlockFieldset | HtmlBlockForm | HtmlBlockH1 | HtmlBlockH2 | HtmlBlockH3 | HtmlBlockH4 | HtmlBlockH5 | HtmlBlockH6 | HtmlBlockMenu | HtmlBlockNoframes | HtmlBlockNoscript | HtmlBlockOl | HtmlBlockP | HtmlBlockPre | HtmlBlockTable | HtmlBlockUl | HtmlBlockDd | HtmlBlockDt | HtmlBlockFrameset | HtmlBlockLi | HtmlBlockTbody | HtmlBlockTd | HtmlBlockTfoot | HtmlBlockTh | HtmlBlockThead | HtmlBlockTr | HtmlBlockScript) + def _HtmlBlockInTags + + _save = self.pos + while true # choice + _tmp = apply(:_HtmlAnchor) + break if _tmp + self.pos = _save + _tmp = apply(:_HtmlBlockAddress) + break if _tmp + self.pos = _save + _tmp = apply(:_HtmlBlockBlockquote) + break if _tmp + self.pos = _save + _tmp = apply(:_HtmlBlockCenter) + break if _tmp + self.pos = _save + _tmp = apply(:_HtmlBlockDir) + break if _tmp + self.pos = _save + _tmp = apply(:_HtmlBlockDiv) + break if _tmp + self.pos = _save + _tmp = apply(:_HtmlBlockDl) + break if _tmp + self.pos = _save + _tmp = apply(:_HtmlBlockFieldset) + break if _tmp + self.pos = _save + _tmp = apply(:_HtmlBlockForm) + break if _tmp + self.pos = _save + _tmp = apply(:_HtmlBlockH1) + break if _tmp + self.pos = _save + _tmp = apply(:_HtmlBlockH2) + break if _tmp + self.pos = _save + _tmp = apply(:_HtmlBlockH3) + break if _tmp + self.pos = _save + _tmp = apply(:_HtmlBlockH4) + break if _tmp + self.pos = _save + _tmp = apply(:_HtmlBlockH5) + break if _tmp + self.pos = _save + _tmp = apply(:_HtmlBlockH6) + break if _tmp + self.pos = _save + _tmp = apply(:_HtmlBlockMenu) + break if _tmp + self.pos = _save + _tmp = apply(:_HtmlBlockNoframes) + break if _tmp + self.pos = _save + _tmp = apply(:_HtmlBlockNoscript) + break if _tmp + self.pos = _save + _tmp = apply(:_HtmlBlockOl) + break if _tmp + self.pos = _save + _tmp = apply(:_HtmlBlockP) + break if _tmp + self.pos = _save + _tmp = apply(:_HtmlBlockPre) + break if _tmp + self.pos = _save + _tmp = apply(:_HtmlBlockTable) + break if _tmp + self.pos = _save + _tmp = apply(:_HtmlBlockUl) + break if _tmp + self.pos = _save + _tmp = apply(:_HtmlBlockDd) + break if _tmp + self.pos = _save + _tmp = apply(:_HtmlBlockDt) + break if _tmp + self.pos = _save + _tmp = apply(:_HtmlBlockFrameset) + break if _tmp + self.pos = _save + _tmp = apply(:_HtmlBlockLi) + break if _tmp + self.pos = _save + _tmp = apply(:_HtmlBlockTbody) + break if _tmp + self.pos = _save + _tmp = apply(:_HtmlBlockTd) + break if _tmp + self.pos = _save + _tmp = apply(:_HtmlBlockTfoot) + break if _tmp + self.pos = _save + _tmp = apply(:_HtmlBlockTh) + break if _tmp + self.pos = _save + _tmp = apply(:_HtmlBlockThead) + break if _tmp + self.pos = _save + _tmp = apply(:_HtmlBlockTr) + break if _tmp + self.pos = _save + _tmp = apply(:_HtmlBlockScript) + break if _tmp + self.pos = _save + break + end # end choice + + set_failed_rule :_HtmlBlockInTags unless _tmp + return _tmp + end + + # HtmlBlock = < (HtmlBlockInTags | HtmlComment | HtmlBlockSelfClosing | HtmlUnclosed) > @BlankLine+ { if html? then RDoc::Markup::Raw.new text end } + def _HtmlBlock + + _save = self.pos + while true # sequence + _text_start = self.pos + + _save1 = self.pos + while true # choice + _tmp = apply(:_HtmlBlockInTags) + break if _tmp + self.pos = _save1 + _tmp = apply(:_HtmlComment) + break if _tmp + self.pos = _save1 + _tmp = apply(:_HtmlBlockSelfClosing) + break if _tmp + self.pos = _save1 + _tmp = apply(:_HtmlUnclosed) + break if _tmp + self.pos = _save1 + break + end # end choice + + if _tmp + text = get_text(_text_start) + end + unless _tmp + self.pos = _save + break + end + _save2 = self.pos + _tmp = _BlankLine() + if _tmp + while true + _tmp = _BlankLine() + break unless _tmp + end + _tmp = true + else + self.pos = _save2 + end + unless _tmp + self.pos = _save + break + end + @result = begin; if html? then + RDoc::Markup::Raw.new text + end ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlock unless _tmp + return _tmp + end + + # HtmlUnclosed = "<" Spnl HtmlUnclosedType Spnl HtmlAttribute* Spnl ">" + def _HtmlUnclosed + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_HtmlUnclosedType) + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + while true + _tmp = apply(:_HtmlAttribute) + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlUnclosed unless _tmp + return _tmp + end + + # HtmlUnclosedType = ("HR" | "hr") + def _HtmlUnclosedType + + _save = self.pos + while true # choice + _tmp = match_string("HR") + break if _tmp + self.pos = _save + _tmp = match_string("hr") + break if _tmp + self.pos = _save + break + end # end choice + + set_failed_rule :_HtmlUnclosedType unless _tmp + return _tmp + end + + # HtmlBlockSelfClosing = "<" Spnl HtmlBlockType Spnl HtmlAttribute* "/" Spnl ">" + def _HtmlBlockSelfClosing + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_HtmlBlockType) + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + while true + _tmp = apply(:_HtmlAttribute) + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = match_string("/") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlBlockSelfClosing unless _tmp + return _tmp + end + + # HtmlBlockType = ("ADDRESS" | "BLOCKQUOTE" | "CENTER" | "DD" | "DIR" | "DIV" | "DL" | "DT" | "FIELDSET" | "FORM" | "FRAMESET" | "H1" | "H2" | "H3" | "H4" | "H5" | "H6" | "HR" | "ISINDEX" | "LI" | "MENU" | "NOFRAMES" | "NOSCRIPT" | "OL" | "P" | "PRE" | "SCRIPT" | "TABLE" | "TBODY" | "TD" | "TFOOT" | "TH" | "THEAD" | "TR" | "UL" | "address" | "blockquote" | "center" | "dd" | "dir" | "div" | "dl" | "dt" | "fieldset" | "form" | "frameset" | "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "hr" | "isindex" | "li" | "menu" | "noframes" | "noscript" | "ol" | "p" | "pre" | "script" | "table" | "tbody" | "td" | "tfoot" | "th" | "thead" | "tr" | "ul") + def _HtmlBlockType + + _save = self.pos + while true # choice + _tmp = match_string("ADDRESS") + break if _tmp + self.pos = _save + _tmp = match_string("BLOCKQUOTE") + break if _tmp + self.pos = _save + _tmp = match_string("CENTER") + break if _tmp + self.pos = _save + _tmp = match_string("DD") + break if _tmp + self.pos = _save + _tmp = match_string("DIR") + break if _tmp + self.pos = _save + _tmp = match_string("DIV") + break if _tmp + self.pos = _save + _tmp = match_string("DL") + break if _tmp + self.pos = _save + _tmp = match_string("DT") + break if _tmp + self.pos = _save + _tmp = match_string("FIELDSET") + break if _tmp + self.pos = _save + _tmp = match_string("FORM") + break if _tmp + self.pos = _save + _tmp = match_string("FRAMESET") + break if _tmp + self.pos = _save + _tmp = match_string("H1") + break if _tmp + self.pos = _save + _tmp = match_string("H2") + break if _tmp + self.pos = _save + _tmp = match_string("H3") + break if _tmp + self.pos = _save + _tmp = match_string("H4") + break if _tmp + self.pos = _save + _tmp = match_string("H5") + break if _tmp + self.pos = _save + _tmp = match_string("H6") + break if _tmp + self.pos = _save + _tmp = match_string("HR") + break if _tmp + self.pos = _save + _tmp = match_string("ISINDEX") + break if _tmp + self.pos = _save + _tmp = match_string("LI") + break if _tmp + self.pos = _save + _tmp = match_string("MENU") + break if _tmp + self.pos = _save + _tmp = match_string("NOFRAMES") + break if _tmp + self.pos = _save + _tmp = match_string("NOSCRIPT") + break if _tmp + self.pos = _save + _tmp = match_string("OL") + break if _tmp + self.pos = _save + _tmp = match_string("P") + break if _tmp + self.pos = _save + _tmp = match_string("PRE") + break if _tmp + self.pos = _save + _tmp = match_string("SCRIPT") + break if _tmp + self.pos = _save + _tmp = match_string("TABLE") + break if _tmp + self.pos = _save + _tmp = match_string("TBODY") + break if _tmp + self.pos = _save + _tmp = match_string("TD") + break if _tmp + self.pos = _save + _tmp = match_string("TFOOT") + break if _tmp + self.pos = _save + _tmp = match_string("TH") + break if _tmp + self.pos = _save + _tmp = match_string("THEAD") + break if _tmp + self.pos = _save + _tmp = match_string("TR") + break if _tmp + self.pos = _save + _tmp = match_string("UL") + break if _tmp + self.pos = _save + _tmp = match_string("address") + break if _tmp + self.pos = _save + _tmp = match_string("blockquote") + break if _tmp + self.pos = _save + _tmp = match_string("center") + break if _tmp + self.pos = _save + _tmp = match_string("dd") + break if _tmp + self.pos = _save + _tmp = match_string("dir") + break if _tmp + self.pos = _save + _tmp = match_string("div") + break if _tmp + self.pos = _save + _tmp = match_string("dl") + break if _tmp + self.pos = _save + _tmp = match_string("dt") + break if _tmp + self.pos = _save + _tmp = match_string("fieldset") + break if _tmp + self.pos = _save + _tmp = match_string("form") + break if _tmp + self.pos = _save + _tmp = match_string("frameset") + break if _tmp + self.pos = _save + _tmp = match_string("h1") + break if _tmp + self.pos = _save + _tmp = match_string("h2") + break if _tmp + self.pos = _save + _tmp = match_string("h3") + break if _tmp + self.pos = _save + _tmp = match_string("h4") + break if _tmp + self.pos = _save + _tmp = match_string("h5") + break if _tmp + self.pos = _save + _tmp = match_string("h6") + break if _tmp + self.pos = _save + _tmp = match_string("hr") + break if _tmp + self.pos = _save + _tmp = match_string("isindex") + break if _tmp + self.pos = _save + _tmp = match_string("li") + break if _tmp + self.pos = _save + _tmp = match_string("menu") + break if _tmp + self.pos = _save + _tmp = match_string("noframes") + break if _tmp + self.pos = _save + _tmp = match_string("noscript") + break if _tmp + self.pos = _save + _tmp = match_string("ol") + break if _tmp + self.pos = _save + _tmp = match_string("p") + break if _tmp + self.pos = _save + _tmp = match_string("pre") + break if _tmp + self.pos = _save + _tmp = match_string("script") + break if _tmp + self.pos = _save + _tmp = match_string("table") + break if _tmp + self.pos = _save + _tmp = match_string("tbody") + break if _tmp + self.pos = _save + _tmp = match_string("td") + break if _tmp + self.pos = _save + _tmp = match_string("tfoot") + break if _tmp + self.pos = _save + _tmp = match_string("th") + break if _tmp + self.pos = _save + _tmp = match_string("thead") + break if _tmp + self.pos = _save + _tmp = match_string("tr") + break if _tmp + self.pos = _save + _tmp = match_string("ul") + break if _tmp + self.pos = _save + break + end # end choice + + set_failed_rule :_HtmlBlockType unless _tmp + return _tmp + end + + # StyleOpen = "<" Spnl ("style" | "STYLE") Spnl HtmlAttribute* ">" + def _StyleOpen + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("style") + break if _tmp + self.pos = _save1 + _tmp = match_string("STYLE") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + while true + _tmp = apply(:_HtmlAttribute) + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_StyleOpen unless _tmp + return _tmp + end + + # StyleClose = "<" Spnl "/" ("style" | "STYLE") Spnl ">" + def _StyleClose + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string("/") + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = match_string("style") + break if _tmp + self.pos = _save1 + _tmp = match_string("STYLE") + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_StyleClose unless _tmp + return _tmp + end + + # InStyleTags = StyleOpen (!StyleClose .)* StyleClose + def _InStyleTags + + _save = self.pos + while true # sequence + _tmp = apply(:_StyleOpen) + unless _tmp + self.pos = _save + break + end + while true + + _save2 = self.pos + while true # sequence + _save3 = self.pos + _tmp = apply(:_StyleClose) + _tmp = _tmp ? nil : true + self.pos = _save3 + unless _tmp + self.pos = _save2 + break + end + _tmp = get_byte + unless _tmp + self.pos = _save2 + end + break + end # end sequence + + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_StyleClose) + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_InStyleTags unless _tmp + return _tmp + end + + # StyleBlock = < InStyleTags > @BlankLine* { if css? then RDoc::Markup::Raw.new text end } + def _StyleBlock + + _save = self.pos + while true # sequence + _text_start = self.pos + _tmp = apply(:_InStyleTags) + if _tmp + text = get_text(_text_start) + end + unless _tmp + self.pos = _save + break + end + while true + _tmp = _BlankLine() + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + @result = begin; if css? then + RDoc::Markup::Raw.new text + end ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_StyleBlock unless _tmp + return _tmp + end + + # Inlines = (!@Endline Inline:i { i } | @Endline:c &Inline { c })+:chunks @Endline? { chunks } + def _Inlines + + _save = self.pos + while true # sequence + _save1 = self.pos + _ary = [] + + _save2 = self.pos + while true # choice + + _save3 = self.pos + while true # sequence + _save4 = self.pos + _tmp = _Endline() + _tmp = _tmp ? nil : true + self.pos = _save4 + unless _tmp + self.pos = _save3 + break + end + _tmp = apply(:_Inline) + i = @result + unless _tmp + self.pos = _save3 + break + end + @result = begin; i ; end + _tmp = true + unless _tmp + self.pos = _save3 + end + break + end # end sequence + + break if _tmp + self.pos = _save2 + + _save5 = self.pos + while true # sequence + _tmp = _Endline() + c = @result + unless _tmp + self.pos = _save5 + break + end + _save6 = self.pos + _tmp = apply(:_Inline) + self.pos = _save6 + unless _tmp + self.pos = _save5 + break + end + @result = begin; c ; end + _tmp = true + unless _tmp + self.pos = _save5 + end + break + end # end sequence + + break if _tmp + self.pos = _save2 + break + end # end choice + + if _tmp + _ary << @result + while true + + _save7 = self.pos + while true # choice + + _save8 = self.pos + while true # sequence + _save9 = self.pos + _tmp = _Endline() + _tmp = _tmp ? nil : true + self.pos = _save9 + unless _tmp + self.pos = _save8 + break + end + _tmp = apply(:_Inline) + i = @result + unless _tmp + self.pos = _save8 + break + end + @result = begin; i ; end + _tmp = true + unless _tmp + self.pos = _save8 + end + break + end # end sequence + + break if _tmp + self.pos = _save7 + + _save10 = self.pos + while true # sequence + _tmp = _Endline() + c = @result + unless _tmp + self.pos = _save10 + break + end + _save11 = self.pos + _tmp = apply(:_Inline) + self.pos = _save11 + unless _tmp + self.pos = _save10 + break + end + @result = begin; c ; end + _tmp = true + unless _tmp + self.pos = _save10 + end + break + end # end sequence + + break if _tmp + self.pos = _save7 + break + end # end choice + + _ary << @result if _tmp + break unless _tmp + end + _tmp = true + @result = _ary + else + self.pos = _save1 + end + chunks = @result + unless _tmp + self.pos = _save + break + end + _save12 = self.pos + _tmp = _Endline() + unless _tmp + _tmp = true + self.pos = _save12 + end + unless _tmp + self.pos = _save + break + end + @result = begin; chunks ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_Inlines unless _tmp + return _tmp + end + + # Inline = (Str | @Endline | UlOrStarLine | @Space | Strong | Emph | Image | Link | NoteReference | InlineNote | Code | RawHtml | Entity | EscapedChar | Symbol) + def _Inline + + _save = self.pos + while true # choice + _tmp = apply(:_Str) + break if _tmp + self.pos = _save + _tmp = _Endline() + break if _tmp + self.pos = _save + _tmp = apply(:_UlOrStarLine) + break if _tmp + self.pos = _save + _tmp = _Space() + break if _tmp + self.pos = _save + _tmp = apply(:_Strong) + break if _tmp + self.pos = _save + _tmp = apply(:_Emph) + break if _tmp + self.pos = _save + _tmp = apply(:_Image) + break if _tmp + self.pos = _save + _tmp = apply(:_Link) + break if _tmp + self.pos = _save + _tmp = apply(:_NoteReference) + break if _tmp + self.pos = _save + _tmp = apply(:_InlineNote) + break if _tmp + self.pos = _save + _tmp = apply(:_Code) + break if _tmp + self.pos = _save + _tmp = apply(:_RawHtml) + break if _tmp + self.pos = _save + _tmp = apply(:_Entity) + break if _tmp + self.pos = _save + _tmp = apply(:_EscapedChar) + break if _tmp + self.pos = _save + _tmp = apply(:_Symbol) + break if _tmp + self.pos = _save + break + end # end choice + + set_failed_rule :_Inline unless _tmp + return _tmp + end + + # Space = @Spacechar+ { " " } + def _Space + + _save = self.pos + while true # sequence + _save1 = self.pos + _tmp = _Spacechar() + if _tmp + while true + _tmp = _Spacechar() + break unless _tmp + end + _tmp = true + else + self.pos = _save1 + end + unless _tmp + self.pos = _save + break + end + @result = begin; " " ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_Space unless _tmp + return _tmp + end + + # Str = @StartList:a < @NormalChar+ > { a = text } (StrChunk:c { a << c })* { a } + def _Str + + _save = self.pos + while true # sequence + _tmp = _StartList() + a = @result + unless _tmp + self.pos = _save + break + end + _text_start = self.pos + _save1 = self.pos + _tmp = _NormalChar() + if _tmp + while true + _tmp = _NormalChar() + break unless _tmp + end + _tmp = true + else + self.pos = _save1 + end + if _tmp + text = get_text(_text_start) + end + unless _tmp + self.pos = _save + break + end + @result = begin; a = text ; end + _tmp = true + unless _tmp + self.pos = _save + break + end + while true + + _save3 = self.pos + while true # sequence + _tmp = apply(:_StrChunk) + c = @result + unless _tmp + self.pos = _save3 + break + end + @result = begin; a << c ; end + _tmp = true + unless _tmp + self.pos = _save3 + end + break + end # end sequence + + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + @result = begin; a ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_Str unless _tmp + return _tmp + end + + # StrChunk = < (@NormalChar | /_+/ &Alphanumeric)+ > { text } + def _StrChunk + + _save = self.pos + while true # sequence + _text_start = self.pos + _save1 = self.pos + + _save2 = self.pos + while true # choice + _tmp = _NormalChar() + break if _tmp + self.pos = _save2 + + _save3 = self.pos + while true # sequence + _tmp = scan(/\A(?-mix:_+)/) + unless _tmp + self.pos = _save3 + break + end + _save4 = self.pos + _tmp = apply(:_Alphanumeric) + self.pos = _save4 + unless _tmp + self.pos = _save3 + end + break + end # end sequence + + break if _tmp + self.pos = _save2 + break + end # end choice + + if _tmp + while true + + _save5 = self.pos + while true # choice + _tmp = _NormalChar() + break if _tmp + self.pos = _save5 + + _save6 = self.pos + while true # sequence + _tmp = scan(/\A(?-mix:_+)/) + unless _tmp + self.pos = _save6 + break + end + _save7 = self.pos + _tmp = apply(:_Alphanumeric) + self.pos = _save7 + unless _tmp + self.pos = _save6 + end + break + end # end sequence + + break if _tmp + self.pos = _save5 + break + end # end choice + + break unless _tmp + end + _tmp = true + else + self.pos = _save1 + end + if _tmp + text = get_text(_text_start) + end + unless _tmp + self.pos = _save + break + end + @result = begin; text ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_StrChunk unless _tmp + return _tmp + end + + # EscapedChar = "\\" !@Newline < /[:\\`|*_{}\[\]()#+.!><-]/ > { text } + def _EscapedChar + + _save = self.pos + while true # sequence + _tmp = match_string("\\") + unless _tmp + self.pos = _save + break + end + _save1 = self.pos + _tmp = _Newline() + _tmp = _tmp ? nil : true + self.pos = _save1 + unless _tmp + self.pos = _save + break + end + _text_start = self.pos + _tmp = scan(/\A(?-mix:[:\\`|*_{}\[\]()#+.!><-])/) + if _tmp + text = get_text(_text_start) + end + unless _tmp + self.pos = _save + break + end + @result = begin; text ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_EscapedChar unless _tmp + return _tmp + end + + # Entity = (HexEntity | DecEntity | CharEntity):a { a } + def _Entity + + _save = self.pos + while true # sequence + + _save1 = self.pos + while true # choice + _tmp = apply(:_HexEntity) + break if _tmp + self.pos = _save1 + _tmp = apply(:_DecEntity) + break if _tmp + self.pos = _save1 + _tmp = apply(:_CharEntity) + break if _tmp + self.pos = _save1 + break + end # end choice + + a = @result + unless _tmp + self.pos = _save + break + end + @result = begin; a ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_Entity unless _tmp + return _tmp + end + + # Endline = (@LineBreak | @TerminalEndline | @NormalEndline) + def _Endline + + _save = self.pos + while true # choice + _tmp = _LineBreak() + break if _tmp + self.pos = _save + _tmp = _TerminalEndline() + break if _tmp + self.pos = _save + _tmp = _NormalEndline() + break if _tmp + self.pos = _save + break + end # end choice + + set_failed_rule :_Endline unless _tmp + return _tmp + end + + # NormalEndline = @Sp @Newline !@BlankLine !">" !AtxStart !(Line /={3,}|-{3,}=/ @Newline) { "\n" } + def _NormalEndline + + _save = self.pos + while true # sequence + _tmp = _Sp() + unless _tmp + self.pos = _save + break + end + _tmp = _Newline() + unless _tmp + self.pos = _save + break + end + _save1 = self.pos + _tmp = _BlankLine() + _tmp = _tmp ? nil : true + self.pos = _save1 + unless _tmp + self.pos = _save + break + end + _save2 = self.pos + _tmp = match_string(">") + _tmp = _tmp ? nil : true + self.pos = _save2 + unless _tmp + self.pos = _save + break + end + _save3 = self.pos + _tmp = apply(:_AtxStart) + _tmp = _tmp ? nil : true + self.pos = _save3 + unless _tmp + self.pos = _save + break + end + _save4 = self.pos + + _save5 = self.pos + while true # sequence + _tmp = apply(:_Line) + unless _tmp + self.pos = _save5 + break + end + _tmp = scan(/\A(?-mix:={3,}|-{3,}=)/) + unless _tmp + self.pos = _save5 + break + end + _tmp = _Newline() + unless _tmp + self.pos = _save5 + end + break + end # end sequence + + _tmp = _tmp ? nil : true + self.pos = _save4 + unless _tmp + self.pos = _save + break + end + @result = begin; "\n" ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_NormalEndline unless _tmp + return _tmp + end + + # TerminalEndline = @Sp @Newline @Eof + def _TerminalEndline + + _save = self.pos + while true # sequence + _tmp = _Sp() + unless _tmp + self.pos = _save + break + end + _tmp = _Newline() + unless _tmp + self.pos = _save + break + end + _tmp = _Eof() + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_TerminalEndline unless _tmp + return _tmp + end + + # LineBreak = " " @NormalEndline { RDoc::Markup::HardBreak.new } + def _LineBreak + + _save = self.pos + while true # sequence + _tmp = match_string(" ") + unless _tmp + self.pos = _save + break + end + _tmp = _NormalEndline() + unless _tmp + self.pos = _save + break + end + @result = begin; RDoc::Markup::HardBreak.new ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_LineBreak unless _tmp + return _tmp + end + + # Symbol = < @SpecialChar > { text } + def _Symbol + + _save = self.pos + while true # sequence + _text_start = self.pos + _tmp = _SpecialChar() + if _tmp + text = get_text(_text_start) + end + unless _tmp + self.pos = _save + break + end + @result = begin; text ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_Symbol unless _tmp + return _tmp + end + + # UlOrStarLine = (UlLine | StarLine):a { a } + def _UlOrStarLine + + _save = self.pos + while true # sequence + + _save1 = self.pos + while true # choice + _tmp = apply(:_UlLine) + break if _tmp + self.pos = _save1 + _tmp = apply(:_StarLine) + break if _tmp + self.pos = _save1 + break + end # end choice + + a = @result + unless _tmp + self.pos = _save + break + end + @result = begin; a ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_UlOrStarLine unless _tmp + return _tmp + end + + # StarLine = (< /\*{4,}/ > { text } | < @Spacechar /\*+/ &@Spacechar > { text }) + def _StarLine + + _save = self.pos + while true # choice + + _save1 = self.pos + while true # sequence + _text_start = self.pos + _tmp = scan(/\A(?-mix:\*{4,})/) + if _tmp + text = get_text(_text_start) + end + unless _tmp + self.pos = _save1 + break + end + @result = begin; text ; end + _tmp = true + unless _tmp + self.pos = _save1 + end + break + end # end sequence + + break if _tmp + self.pos = _save + + _save2 = self.pos + while true # sequence + _text_start = self.pos + + _save3 = self.pos + while true # sequence + _tmp = _Spacechar() + unless _tmp + self.pos = _save3 + break + end + _tmp = scan(/\A(?-mix:\*+)/) + unless _tmp + self.pos = _save3 + break + end + _save4 = self.pos + _tmp = _Spacechar() + self.pos = _save4 + unless _tmp + self.pos = _save3 + end + break + end # end sequence + + if _tmp + text = get_text(_text_start) + end + unless _tmp + self.pos = _save2 + break + end + @result = begin; text ; end + _tmp = true + unless _tmp + self.pos = _save2 + end + break + end # end sequence + + break if _tmp + self.pos = _save + break + end # end choice + + set_failed_rule :_StarLine unless _tmp + return _tmp + end + + # UlLine = (< /_{4,}/ > { text } | < @Spacechar /_+/ &@Spacechar > { text }) + def _UlLine + + _save = self.pos + while true # choice + + _save1 = self.pos + while true # sequence + _text_start = self.pos + _tmp = scan(/\A(?-mix:_{4,})/) + if _tmp + text = get_text(_text_start) + end + unless _tmp + self.pos = _save1 + break + end + @result = begin; text ; end + _tmp = true + unless _tmp + self.pos = _save1 + end + break + end # end sequence + + break if _tmp + self.pos = _save + + _save2 = self.pos + while true # sequence + _text_start = self.pos + + _save3 = self.pos + while true # sequence + _tmp = _Spacechar() + unless _tmp + self.pos = _save3 + break + end + _tmp = scan(/\A(?-mix:_+)/) + unless _tmp + self.pos = _save3 + break + end + _save4 = self.pos + _tmp = _Spacechar() + self.pos = _save4 + unless _tmp + self.pos = _save3 + end + break + end # end sequence + + if _tmp + text = get_text(_text_start) + end + unless _tmp + self.pos = _save2 + break + end + @result = begin; text ; end + _tmp = true + unless _tmp + self.pos = _save2 + end + break + end # end sequence + + break if _tmp + self.pos = _save + break + end # end choice + + set_failed_rule :_UlLine unless _tmp + return _tmp + end + + # Emph = (EmphStar | EmphUl) + def _Emph + + _save = self.pos + while true # choice + _tmp = apply(:_EmphStar) + break if _tmp + self.pos = _save + _tmp = apply(:_EmphUl) + break if _tmp + self.pos = _save + break + end # end choice + + set_failed_rule :_Emph unless _tmp + return _tmp + end + + # OneStarOpen = !StarLine "*" !@Spacechar !@Newline + def _OneStarOpen + + _save = self.pos + while true # sequence + _save1 = self.pos + _tmp = apply(:_StarLine) + _tmp = _tmp ? nil : true + self.pos = _save1 + unless _tmp + self.pos = _save + break + end + _tmp = match_string("*") + unless _tmp + self.pos = _save + break + end + _save2 = self.pos + _tmp = _Spacechar() + _tmp = _tmp ? nil : true + self.pos = _save2 + unless _tmp + self.pos = _save + break + end + _save3 = self.pos + _tmp = _Newline() + _tmp = _tmp ? nil : true + self.pos = _save3 + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_OneStarOpen unless _tmp + return _tmp + end + + # OneStarClose = !@Spacechar !@Newline Inline:a "*" { a } + def _OneStarClose + + _save = self.pos + while true # sequence + _save1 = self.pos + _tmp = _Spacechar() + _tmp = _tmp ? nil : true + self.pos = _save1 + unless _tmp + self.pos = _save + break + end + _save2 = self.pos + _tmp = _Newline() + _tmp = _tmp ? nil : true + self.pos = _save2 + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Inline) + a = @result + unless _tmp + self.pos = _save + break + end + _tmp = match_string("*") + unless _tmp + self.pos = _save + break + end + @result = begin; a ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_OneStarClose unless _tmp + return _tmp + end + + # EmphStar = OneStarOpen @StartList:a (!OneStarClose Inline:l { a << l })* OneStarClose:l { a << l } { emphasis a.join } + def _EmphStar + + _save = self.pos + while true # sequence + _tmp = apply(:_OneStarOpen) + unless _tmp + self.pos = _save + break + end + _tmp = _StartList() + a = @result + unless _tmp + self.pos = _save + break + end + while true + + _save2 = self.pos + while true # sequence + _save3 = self.pos + _tmp = apply(:_OneStarClose) + _tmp = _tmp ? nil : true + self.pos = _save3 + unless _tmp + self.pos = _save2 + break + end + _tmp = apply(:_Inline) + l = @result + unless _tmp + self.pos = _save2 + break + end + @result = begin; a << l ; end + _tmp = true + unless _tmp + self.pos = _save2 + end + break + end # end sequence + + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_OneStarClose) + l = @result + unless _tmp + self.pos = _save + break + end + @result = begin; a << l ; end + _tmp = true + unless _tmp + self.pos = _save + break + end + @result = begin; emphasis a.join ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_EmphStar unless _tmp + return _tmp + end + + # OneUlOpen = !UlLine "_" !@Spacechar !@Newline + def _OneUlOpen + + _save = self.pos + while true # sequence + _save1 = self.pos + _tmp = apply(:_UlLine) + _tmp = _tmp ? nil : true + self.pos = _save1 + unless _tmp + self.pos = _save + break + end + _tmp = match_string("_") + unless _tmp + self.pos = _save + break + end + _save2 = self.pos + _tmp = _Spacechar() + _tmp = _tmp ? nil : true + self.pos = _save2 + unless _tmp + self.pos = _save + break + end + _save3 = self.pos + _tmp = _Newline() + _tmp = _tmp ? nil : true + self.pos = _save3 + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_OneUlOpen unless _tmp + return _tmp + end + + # OneUlClose = !@Spacechar !@Newline Inline:a "_" { a } + def _OneUlClose + + _save = self.pos + while true # sequence + _save1 = self.pos + _tmp = _Spacechar() + _tmp = _tmp ? nil : true + self.pos = _save1 + unless _tmp + self.pos = _save + break + end + _save2 = self.pos + _tmp = _Newline() + _tmp = _tmp ? nil : true + self.pos = _save2 + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Inline) + a = @result + unless _tmp + self.pos = _save + break + end + _tmp = match_string("_") + unless _tmp + self.pos = _save + break + end + @result = begin; a ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_OneUlClose unless _tmp + return _tmp + end + + # EmphUl = OneUlOpen @StartList:a (!OneUlClose Inline:l { a << l })* OneUlClose:l { a << l } { emphasis a.join } + def _EmphUl + + _save = self.pos + while true # sequence + _tmp = apply(:_OneUlOpen) + unless _tmp + self.pos = _save + break + end + _tmp = _StartList() + a = @result + unless _tmp + self.pos = _save + break + end + while true + + _save2 = self.pos + while true # sequence + _save3 = self.pos + _tmp = apply(:_OneUlClose) + _tmp = _tmp ? nil : true + self.pos = _save3 + unless _tmp + self.pos = _save2 + break + end + _tmp = apply(:_Inline) + l = @result + unless _tmp + self.pos = _save2 + break + end + @result = begin; a << l ; end + _tmp = true + unless _tmp + self.pos = _save2 + end + break + end # end sequence + + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_OneUlClose) + l = @result + unless _tmp + self.pos = _save + break + end + @result = begin; a << l ; end + _tmp = true + unless _tmp + self.pos = _save + break + end + @result = begin; emphasis a.join ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_EmphUl unless _tmp + return _tmp + end + + # Strong = (StrongStar | StrongUl) + def _Strong + + _save = self.pos + while true # choice + _tmp = apply(:_StrongStar) + break if _tmp + self.pos = _save + _tmp = apply(:_StrongUl) + break if _tmp + self.pos = _save + break + end # end choice + + set_failed_rule :_Strong unless _tmp + return _tmp + end + + # TwoStarOpen = !StarLine "**" !@Spacechar !@Newline + def _TwoStarOpen + + _save = self.pos + while true # sequence + _save1 = self.pos + _tmp = apply(:_StarLine) + _tmp = _tmp ? nil : true + self.pos = _save1 + unless _tmp + self.pos = _save + break + end + _tmp = match_string("**") + unless _tmp + self.pos = _save + break + end + _save2 = self.pos + _tmp = _Spacechar() + _tmp = _tmp ? nil : true + self.pos = _save2 + unless _tmp + self.pos = _save + break + end + _save3 = self.pos + _tmp = _Newline() + _tmp = _tmp ? nil : true + self.pos = _save3 + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_TwoStarOpen unless _tmp + return _tmp + end + + # TwoStarClose = !@Spacechar !@Newline Inline:a "**" { a } + def _TwoStarClose + + _save = self.pos + while true # sequence + _save1 = self.pos + _tmp = _Spacechar() + _tmp = _tmp ? nil : true + self.pos = _save1 + unless _tmp + self.pos = _save + break + end + _save2 = self.pos + _tmp = _Newline() + _tmp = _tmp ? nil : true + self.pos = _save2 + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Inline) + a = @result + unless _tmp + self.pos = _save + break + end + _tmp = match_string("**") + unless _tmp + self.pos = _save + break + end + @result = begin; a ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_TwoStarClose unless _tmp + return _tmp + end + + # StrongStar = TwoStarOpen @StartList:a (!TwoStarClose Inline:l { a << l })* TwoStarClose:l { a << l } { strong a.join } + def _StrongStar + + _save = self.pos + while true # sequence + _tmp = apply(:_TwoStarOpen) + unless _tmp + self.pos = _save + break + end + _tmp = _StartList() + a = @result + unless _tmp + self.pos = _save + break + end + while true + + _save2 = self.pos + while true # sequence + _save3 = self.pos + _tmp = apply(:_TwoStarClose) + _tmp = _tmp ? nil : true + self.pos = _save3 + unless _tmp + self.pos = _save2 + break + end + _tmp = apply(:_Inline) + l = @result + unless _tmp + self.pos = _save2 + break + end + @result = begin; a << l ; end + _tmp = true + unless _tmp + self.pos = _save2 + end + break + end # end sequence + + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_TwoStarClose) + l = @result + unless _tmp + self.pos = _save + break + end + @result = begin; a << l ; end + _tmp = true + unless _tmp + self.pos = _save + break + end + @result = begin; strong a.join ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_StrongStar unless _tmp + return _tmp + end + + # TwoUlOpen = !UlLine "__" !@Spacechar !@Newline + def _TwoUlOpen + + _save = self.pos + while true # sequence + _save1 = self.pos + _tmp = apply(:_UlLine) + _tmp = _tmp ? nil : true + self.pos = _save1 + unless _tmp + self.pos = _save + break + end + _tmp = match_string("__") + unless _tmp + self.pos = _save + break + end + _save2 = self.pos + _tmp = _Spacechar() + _tmp = _tmp ? nil : true + self.pos = _save2 + unless _tmp + self.pos = _save + break + end + _save3 = self.pos + _tmp = _Newline() + _tmp = _tmp ? nil : true + self.pos = _save3 + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_TwoUlOpen unless _tmp + return _tmp + end + + # TwoUlClose = !@Spacechar !@Newline Inline:a "__" { a } + def _TwoUlClose + + _save = self.pos + while true # sequence + _save1 = self.pos + _tmp = _Spacechar() + _tmp = _tmp ? nil : true + self.pos = _save1 + unless _tmp + self.pos = _save + break + end + _save2 = self.pos + _tmp = _Newline() + _tmp = _tmp ? nil : true + self.pos = _save2 + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Inline) + a = @result + unless _tmp + self.pos = _save + break + end + _tmp = match_string("__") + unless _tmp + self.pos = _save + break + end + @result = begin; a ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_TwoUlClose unless _tmp + return _tmp + end + + # StrongUl = TwoUlOpen @StartList:a (!TwoUlClose Inline:i { a << i })* TwoUlClose:l { a << l } { strong a.join } + def _StrongUl + + _save = self.pos + while true # sequence + _tmp = apply(:_TwoUlOpen) + unless _tmp + self.pos = _save + break + end + _tmp = _StartList() + a = @result + unless _tmp + self.pos = _save + break + end + while true + + _save2 = self.pos + while true # sequence + _save3 = self.pos + _tmp = apply(:_TwoUlClose) + _tmp = _tmp ? nil : true + self.pos = _save3 + unless _tmp + self.pos = _save2 + break + end + _tmp = apply(:_Inline) + i = @result + unless _tmp + self.pos = _save2 + break + end + @result = begin; a << i ; end + _tmp = true + unless _tmp + self.pos = _save2 + end + break + end # end sequence + + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_TwoUlClose) + l = @result + unless _tmp + self.pos = _save + break + end + @result = begin; a << l ; end + _tmp = true + unless _tmp + self.pos = _save + break + end + @result = begin; strong a.join ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_StrongUl unless _tmp + return _tmp + end + + # Image = "!" (ExplicitLink | ReferenceLink):a { "rdoc-image:#{a[/\[(.*)\]/, 1]}" } + def _Image + + _save = self.pos + while true # sequence + _tmp = match_string("!") + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + _tmp = apply(:_ExplicitLink) + break if _tmp + self.pos = _save1 + _tmp = apply(:_ReferenceLink) + break if _tmp + self.pos = _save1 + break + end # end choice + + a = @result + unless _tmp + self.pos = _save + break + end + @result = begin; "rdoc-image:#{a[/\[(.*)\]/, 1]}" ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_Image unless _tmp + return _tmp + end + + # Link = (ExplicitLink | ReferenceLink | AutoLink) + def _Link + + _save = self.pos + while true # choice + _tmp = apply(:_ExplicitLink) + break if _tmp + self.pos = _save + _tmp = apply(:_ReferenceLink) + break if _tmp + self.pos = _save + _tmp = apply(:_AutoLink) + break if _tmp + self.pos = _save + break + end # end choice + + set_failed_rule :_Link unless _tmp + return _tmp + end + + # ReferenceLink = (ReferenceLinkDouble | ReferenceLinkSingle) + def _ReferenceLink + + _save = self.pos + while true # choice + _tmp = apply(:_ReferenceLinkDouble) + break if _tmp + self.pos = _save + _tmp = apply(:_ReferenceLinkSingle) + break if _tmp + self.pos = _save + break + end # end choice + + set_failed_rule :_ReferenceLink unless _tmp + return _tmp + end + + # ReferenceLinkDouble = Label:content < Spnl > !"[]" Label:label { link_to content, label, text } + def _ReferenceLinkDouble + + _save = self.pos + while true # sequence + _tmp = apply(:_Label) + content = @result + unless _tmp + self.pos = _save + break + end + _text_start = self.pos + _tmp = apply(:_Spnl) + if _tmp + text = get_text(_text_start) + end + unless _tmp + self.pos = _save + break + end + _save1 = self.pos + _tmp = match_string("[]") + _tmp = _tmp ? nil : true + self.pos = _save1 + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Label) + label = @result + unless _tmp + self.pos = _save + break + end + @result = begin; link_to content, label, text ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_ReferenceLinkDouble unless _tmp + return _tmp + end + + # ReferenceLinkSingle = Label:content < (Spnl "[]")? > { link_to content, content, text } + def _ReferenceLinkSingle + + _save = self.pos + while true # sequence + _tmp = apply(:_Label) + content = @result + unless _tmp + self.pos = _save + break + end + _text_start = self.pos + _save1 = self.pos + + _save2 = self.pos + while true # sequence + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save2 + break + end + _tmp = match_string("[]") + unless _tmp + self.pos = _save2 + end + break + end # end sequence + + unless _tmp + _tmp = true + self.pos = _save1 + end + if _tmp + text = get_text(_text_start) + end + unless _tmp + self.pos = _save + break + end + @result = begin; link_to content, content, text ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_ReferenceLinkSingle unless _tmp + return _tmp + end + + # ExplicitLink = Label:l Spnl "(" @Sp Source:s Spnl Title @Sp ")" { "{#{l}}[#{s}]" } + def _ExplicitLink + + _save = self.pos + while true # sequence + _tmp = apply(:_Label) + l = @result + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string("(") + unless _tmp + self.pos = _save + break + end + _tmp = _Sp() + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Source) + s = @result + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Title) + unless _tmp + self.pos = _save + break + end + _tmp = _Sp() + unless _tmp + self.pos = _save + break + end + _tmp = match_string(")") + unless _tmp + self.pos = _save + break + end + @result = begin; "{#{l}}[#{s}]" ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_ExplicitLink unless _tmp + return _tmp + end + + # Source = ("<" < SourceContents > ">" | < SourceContents >) { text } + def _Source + + _save = self.pos + while true # sequence + + _save1 = self.pos + while true # choice + + _save2 = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save2 + break + end + _text_start = self.pos + _tmp = apply(:_SourceContents) + if _tmp + text = get_text(_text_start) + end + unless _tmp + self.pos = _save2 + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save2 + end + break + end # end sequence + + break if _tmp + self.pos = _save1 + _text_start = self.pos + _tmp = apply(:_SourceContents) + if _tmp + text = get_text(_text_start) + end + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + @result = begin; text ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_Source unless _tmp + return _tmp + end + + # SourceContents = (((!"(" !")" !">" Nonspacechar)+ | "(" SourceContents ")")* | "") + def _SourceContents + + _save = self.pos + while true # choice + while true + + _save2 = self.pos + while true # choice + _save3 = self.pos + + _save4 = self.pos + while true # sequence + _save5 = self.pos + _tmp = match_string("(") + _tmp = _tmp ? nil : true + self.pos = _save5 + unless _tmp + self.pos = _save4 + break + end + _save6 = self.pos + _tmp = match_string(")") + _tmp = _tmp ? nil : true + self.pos = _save6 + unless _tmp + self.pos = _save4 + break + end + _save7 = self.pos + _tmp = match_string(">") + _tmp = _tmp ? nil : true + self.pos = _save7 + unless _tmp + self.pos = _save4 + break + end + _tmp = apply(:_Nonspacechar) + unless _tmp + self.pos = _save4 + end + break + end # end sequence + + if _tmp + while true + + _save8 = self.pos + while true # sequence + _save9 = self.pos + _tmp = match_string("(") + _tmp = _tmp ? nil : true + self.pos = _save9 + unless _tmp + self.pos = _save8 + break + end + _save10 = self.pos + _tmp = match_string(")") + _tmp = _tmp ? nil : true + self.pos = _save10 + unless _tmp + self.pos = _save8 + break + end + _save11 = self.pos + _tmp = match_string(">") + _tmp = _tmp ? nil : true + self.pos = _save11 + unless _tmp + self.pos = _save8 + break + end + _tmp = apply(:_Nonspacechar) + unless _tmp + self.pos = _save8 + end + break + end # end sequence + + break unless _tmp + end + _tmp = true + else + self.pos = _save3 + end + break if _tmp + self.pos = _save2 + + _save12 = self.pos + while true # sequence + _tmp = match_string("(") + unless _tmp + self.pos = _save12 + break + end + _tmp = apply(:_SourceContents) + unless _tmp + self.pos = _save12 + break + end + _tmp = match_string(")") + unless _tmp + self.pos = _save12 + end + break + end # end sequence + + break if _tmp + self.pos = _save2 + break + end # end choice + + break unless _tmp + end + _tmp = true + break if _tmp + self.pos = _save + _tmp = match_string("") + break if _tmp + self.pos = _save + break + end # end choice + + set_failed_rule :_SourceContents unless _tmp + return _tmp + end + + # Title = (TitleSingle | TitleDouble | ""):a { a } + def _Title + + _save = self.pos + while true # sequence + + _save1 = self.pos + while true # choice + _tmp = apply(:_TitleSingle) + break if _tmp + self.pos = _save1 + _tmp = apply(:_TitleDouble) + break if _tmp + self.pos = _save1 + _tmp = match_string("") + break if _tmp + self.pos = _save1 + break + end # end choice + + a = @result + unless _tmp + self.pos = _save + break + end + @result = begin; a ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_Title unless _tmp + return _tmp + end + + # TitleSingle = "'" (!("'" @Sp (")" | @Newline)) .)* "'" + def _TitleSingle + + _save = self.pos + while true # sequence + _tmp = match_string("'") + unless _tmp + self.pos = _save + break + end + while true + + _save2 = self.pos + while true # sequence + _save3 = self.pos + + _save4 = self.pos + while true # sequence + _tmp = match_string("'") + unless _tmp + self.pos = _save4 + break + end + _tmp = _Sp() + unless _tmp + self.pos = _save4 + break + end + + _save5 = self.pos + while true # choice + _tmp = match_string(")") + break if _tmp + self.pos = _save5 + _tmp = _Newline() + break if _tmp + self.pos = _save5 + break + end # end choice + + unless _tmp + self.pos = _save4 + end + break + end # end sequence + + _tmp = _tmp ? nil : true + self.pos = _save3 + unless _tmp + self.pos = _save2 + break + end + _tmp = get_byte + unless _tmp + self.pos = _save2 + end + break + end # end sequence + + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = match_string("'") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_TitleSingle unless _tmp + return _tmp + end + + # TitleDouble = "\"" (!("\"" @Sp (")" | @Newline)) .)* "\"" + def _TitleDouble + + _save = self.pos + while true # sequence + _tmp = match_string("\"") + unless _tmp + self.pos = _save + break + end + while true + + _save2 = self.pos + while true # sequence + _save3 = self.pos + + _save4 = self.pos + while true # sequence + _tmp = match_string("\"") + unless _tmp + self.pos = _save4 + break + end + _tmp = _Sp() + unless _tmp + self.pos = _save4 + break + end + + _save5 = self.pos + while true # choice + _tmp = match_string(")") + break if _tmp + self.pos = _save5 + _tmp = _Newline() + break if _tmp + self.pos = _save5 + break + end # end choice + + unless _tmp + self.pos = _save4 + end + break + end # end sequence + + _tmp = _tmp ? nil : true + self.pos = _save3 + unless _tmp + self.pos = _save2 + break + end + _tmp = get_byte + unless _tmp + self.pos = _save2 + end + break + end # end sequence + + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = match_string("\"") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_TitleDouble unless _tmp + return _tmp + end + + # AutoLink = (AutoLinkUrl | AutoLinkEmail) + def _AutoLink + + _save = self.pos + while true # choice + _tmp = apply(:_AutoLinkUrl) + break if _tmp + self.pos = _save + _tmp = apply(:_AutoLinkEmail) + break if _tmp + self.pos = _save + break + end # end choice + + set_failed_rule :_AutoLink unless _tmp + return _tmp + end + + # AutoLinkUrl = "<" < /[A-Za-z]+/ "://" (!@Newline !">" .)+ > ">" { text } + def _AutoLinkUrl + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _text_start = self.pos + + _save1 = self.pos + while true # sequence + _tmp = scan(/\A(?-mix:[A-Za-z]+)/) + unless _tmp + self.pos = _save1 + break + end + _tmp = match_string("://") + unless _tmp + self.pos = _save1 + break + end + _save2 = self.pos + + _save3 = self.pos + while true # sequence + _save4 = self.pos + _tmp = _Newline() + _tmp = _tmp ? nil : true + self.pos = _save4 + unless _tmp + self.pos = _save3 + break + end + _save5 = self.pos + _tmp = match_string(">") + _tmp = _tmp ? nil : true + self.pos = _save5 + unless _tmp + self.pos = _save3 + break + end + _tmp = get_byte + unless _tmp + self.pos = _save3 + end + break + end # end sequence + + if _tmp + while true + + _save6 = self.pos + while true # sequence + _save7 = self.pos + _tmp = _Newline() + _tmp = _tmp ? nil : true + self.pos = _save7 + unless _tmp + self.pos = _save6 + break + end + _save8 = self.pos + _tmp = match_string(">") + _tmp = _tmp ? nil : true + self.pos = _save8 + unless _tmp + self.pos = _save6 + break + end + _tmp = get_byte + unless _tmp + self.pos = _save6 + end + break + end # end sequence + + break unless _tmp + end + _tmp = true + else + self.pos = _save2 + end + unless _tmp + self.pos = _save1 + end + break + end # end sequence + + if _tmp + text = get_text(_text_start) + end + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + break + end + @result = begin; text ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_AutoLinkUrl unless _tmp + return _tmp + end + + # AutoLinkEmail = "<" "mailto:"? < /[\w+.\/!%~$-]+/i "@" (!@Newline !">" .)+ > ">" { "mailto:#{text}" } + def _AutoLinkEmail + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _save1 = self.pos + _tmp = match_string("mailto:") + unless _tmp + _tmp = true + self.pos = _save1 + end + unless _tmp + self.pos = _save + break + end + _text_start = self.pos + + _save2 = self.pos + while true # sequence + _tmp = scan(/\A(?i-mx:[\w+.\/!%~$-]+)/) + unless _tmp + self.pos = _save2 + break + end + _tmp = match_string("@") + unless _tmp + self.pos = _save2 + break + end + _save3 = self.pos + + _save4 = self.pos + while true # sequence + _save5 = self.pos + _tmp = _Newline() + _tmp = _tmp ? nil : true + self.pos = _save5 + unless _tmp + self.pos = _save4 + break + end + _save6 = self.pos + _tmp = match_string(">") + _tmp = _tmp ? nil : true + self.pos = _save6 + unless _tmp + self.pos = _save4 + break + end + _tmp = get_byte + unless _tmp + self.pos = _save4 + end + break + end # end sequence + + if _tmp + while true + + _save7 = self.pos + while true # sequence + _save8 = self.pos + _tmp = _Newline() + _tmp = _tmp ? nil : true + self.pos = _save8 + unless _tmp + self.pos = _save7 + break + end + _save9 = self.pos + _tmp = match_string(">") + _tmp = _tmp ? nil : true + self.pos = _save9 + unless _tmp + self.pos = _save7 + break + end + _tmp = get_byte + unless _tmp + self.pos = _save7 + end + break + end # end sequence + + break unless _tmp + end + _tmp = true + else + self.pos = _save3 + end + unless _tmp + self.pos = _save2 + end + break + end # end sequence + + if _tmp + text = get_text(_text_start) + end + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + break + end + @result = begin; "mailto:#{text}" ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_AutoLinkEmail unless _tmp + return _tmp + end + + # Reference = @NonindentSpace !"[]" Label:label ":" Spnl RefSrc:link RefTitle @BlankLine+ { # TODO use title reference label, link nil } + def _Reference + + _save = self.pos + while true # sequence + _tmp = _NonindentSpace() + unless _tmp + self.pos = _save + break + end + _save1 = self.pos + _tmp = match_string("[]") + _tmp = _tmp ? nil : true + self.pos = _save1 + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Label) + label = @result + unless _tmp + self.pos = _save + break + end + _tmp = match_string(":") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_RefSrc) + link = @result + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_RefTitle) + unless _tmp + self.pos = _save + break + end + _save2 = self.pos + _tmp = _BlankLine() + if _tmp + while true + _tmp = _BlankLine() + break unless _tmp + end + _tmp = true + else + self.pos = _save2 + end + unless _tmp + self.pos = _save + break + end + @result = begin; # TODO use title + reference label, link + nil + ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_Reference unless _tmp + return _tmp + end + + # Label = "[" (!"^" &{ notes? } | &. &{ !notes? }) @StartList:a (!"]" Inline:l { a << l })* "]" { a.join.gsub(/\s+/, ' ') } + def _Label + + _save = self.pos + while true # sequence + _tmp = match_string("[") + unless _tmp + self.pos = _save + break + end + + _save1 = self.pos + while true # choice + + _save2 = self.pos + while true # sequence + _save3 = self.pos + _tmp = match_string("^") + _tmp = _tmp ? nil : true + self.pos = _save3 + unless _tmp + self.pos = _save2 + break + end + _save4 = self.pos + _tmp = begin; notes? ; end + self.pos = _save4 + unless _tmp + self.pos = _save2 + end + break + end # end sequence + + break if _tmp + self.pos = _save1 + + _save5 = self.pos + while true # sequence + _save6 = self.pos + _tmp = get_byte + self.pos = _save6 + unless _tmp + self.pos = _save5 + break + end + _save7 = self.pos + _tmp = begin; !notes? ; end + self.pos = _save7 + unless _tmp + self.pos = _save5 + end + break + end # end sequence + + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + _tmp = _StartList() + a = @result + unless _tmp + self.pos = _save + break + end + while true + + _save9 = self.pos + while true # sequence + _save10 = self.pos + _tmp = match_string("]") + _tmp = _tmp ? nil : true + self.pos = _save10 + unless _tmp + self.pos = _save9 + break + end + _tmp = apply(:_Inline) + l = @result + unless _tmp + self.pos = _save9 + break + end + @result = begin; a << l ; end + _tmp = true + unless _tmp + self.pos = _save9 + end + break + end # end sequence + + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = match_string("]") + unless _tmp + self.pos = _save + break + end + @result = begin; a.join.gsub(/\s+/, ' ') ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_Label unless _tmp + return _tmp + end + + # RefSrc = < Nonspacechar+ > { text } + def _RefSrc + + _save = self.pos + while true # sequence + _text_start = self.pos + _save1 = self.pos + _tmp = apply(:_Nonspacechar) + if _tmp + while true + _tmp = apply(:_Nonspacechar) + break unless _tmp + end + _tmp = true + else + self.pos = _save1 + end + if _tmp + text = get_text(_text_start) + end + unless _tmp + self.pos = _save + break + end + @result = begin; text ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_RefSrc unless _tmp + return _tmp + end + + # RefTitle = (RefTitleSingle | RefTitleDouble | RefTitleParens | EmptyTitle) + def _RefTitle + + _save = self.pos + while true # choice + _tmp = apply(:_RefTitleSingle) + break if _tmp + self.pos = _save + _tmp = apply(:_RefTitleDouble) + break if _tmp + self.pos = _save + _tmp = apply(:_RefTitleParens) + break if _tmp + self.pos = _save + _tmp = apply(:_EmptyTitle) + break if _tmp + self.pos = _save + break + end # end choice + + set_failed_rule :_RefTitle unless _tmp + return _tmp + end + + # EmptyTitle = "" + def _EmptyTitle + _tmp = match_string("") + set_failed_rule :_EmptyTitle unless _tmp + return _tmp + end + + # RefTitleSingle = Spnl "'" < (!("'" @Sp @Newline | @Newline) .)* > "'" { text } + def _RefTitleSingle + + _save = self.pos + while true # sequence + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string("'") + unless _tmp + self.pos = _save + break + end + _text_start = self.pos + while true + + _save2 = self.pos + while true # sequence + _save3 = self.pos + + _save4 = self.pos + while true # choice + + _save5 = self.pos + while true # sequence + _tmp = match_string("'") + unless _tmp + self.pos = _save5 + break + end + _tmp = _Sp() + unless _tmp + self.pos = _save5 + break + end + _tmp = _Newline() + unless _tmp + self.pos = _save5 + end + break + end # end sequence + + break if _tmp + self.pos = _save4 + _tmp = _Newline() + break if _tmp + self.pos = _save4 + break + end # end choice + + _tmp = _tmp ? nil : true + self.pos = _save3 + unless _tmp + self.pos = _save2 + break + end + _tmp = get_byte + unless _tmp + self.pos = _save2 + end + break + end # end sequence + + break unless _tmp + end + _tmp = true + if _tmp + text = get_text(_text_start) + end + unless _tmp + self.pos = _save + break + end + _tmp = match_string("'") + unless _tmp + self.pos = _save + break + end + @result = begin; text ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_RefTitleSingle unless _tmp + return _tmp + end + + # RefTitleDouble = Spnl "\"" < (!("\"" @Sp @Newline | @Newline) .)* > "\"" { text } + def _RefTitleDouble + + _save = self.pos + while true # sequence + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string("\"") + unless _tmp + self.pos = _save + break + end + _text_start = self.pos + while true + + _save2 = self.pos + while true # sequence + _save3 = self.pos + + _save4 = self.pos + while true # choice + + _save5 = self.pos + while true # sequence + _tmp = match_string("\"") + unless _tmp + self.pos = _save5 + break + end + _tmp = _Sp() + unless _tmp + self.pos = _save5 + break + end + _tmp = _Newline() + unless _tmp + self.pos = _save5 + end + break + end # end sequence + + break if _tmp + self.pos = _save4 + _tmp = _Newline() + break if _tmp + self.pos = _save4 + break + end # end choice + + _tmp = _tmp ? nil : true + self.pos = _save3 + unless _tmp + self.pos = _save2 + break + end + _tmp = get_byte + unless _tmp + self.pos = _save2 + end + break + end # end sequence + + break unless _tmp + end + _tmp = true + if _tmp + text = get_text(_text_start) + end + unless _tmp + self.pos = _save + break + end + _tmp = match_string("\"") + unless _tmp + self.pos = _save + break + end + @result = begin; text ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_RefTitleDouble unless _tmp + return _tmp + end + + # RefTitleParens = Spnl "(" < (!(")" @Sp @Newline | @Newline) .)* > ")" { text } + def _RefTitleParens + + _save = self.pos + while true # sequence + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string("(") + unless _tmp + self.pos = _save + break + end + _text_start = self.pos + while true + + _save2 = self.pos + while true # sequence + _save3 = self.pos + + _save4 = self.pos + while true # choice + + _save5 = self.pos + while true # sequence + _tmp = match_string(")") + unless _tmp + self.pos = _save5 + break + end + _tmp = _Sp() + unless _tmp + self.pos = _save5 + break + end + _tmp = _Newline() + unless _tmp + self.pos = _save5 + end + break + end # end sequence + + break if _tmp + self.pos = _save4 + _tmp = _Newline() + break if _tmp + self.pos = _save4 + break + end # end choice + + _tmp = _tmp ? nil : true + self.pos = _save3 + unless _tmp + self.pos = _save2 + break + end + _tmp = get_byte + unless _tmp + self.pos = _save2 + end + break + end # end sequence + + break unless _tmp + end + _tmp = true + if _tmp + text = get_text(_text_start) + end + unless _tmp + self.pos = _save + break + end + _tmp = match_string(")") + unless _tmp + self.pos = _save + break + end + @result = begin; text ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_RefTitleParens unless _tmp + return _tmp + end + + # References = (Reference | SkipBlock)* + def _References + while true + + _save1 = self.pos + while true # choice + _tmp = apply(:_Reference) + break if _tmp + self.pos = _save1 + _tmp = apply(:_SkipBlock) + break if _tmp + self.pos = _save1 + break + end # end choice + + break unless _tmp + end + _tmp = true + set_failed_rule :_References unless _tmp + return _tmp + end + + # Ticks1 = "`" !"`" + def _Ticks1 + + _save = self.pos + while true # sequence + _tmp = match_string("`") + unless _tmp + self.pos = _save + break + end + _save1 = self.pos + _tmp = match_string("`") + _tmp = _tmp ? nil : true + self.pos = _save1 + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_Ticks1 unless _tmp + return _tmp + end + + # Ticks2 = "``" !"`" + def _Ticks2 + + _save = self.pos + while true # sequence + _tmp = match_string("``") + unless _tmp + self.pos = _save + break + end + _save1 = self.pos + _tmp = match_string("`") + _tmp = _tmp ? nil : true + self.pos = _save1 + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_Ticks2 unless _tmp + return _tmp + end + + # Ticks3 = "```" !"`" + def _Ticks3 + + _save = self.pos + while true # sequence + _tmp = match_string("```") + unless _tmp + self.pos = _save + break + end + _save1 = self.pos + _tmp = match_string("`") + _tmp = _tmp ? nil : true + self.pos = _save1 + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_Ticks3 unless _tmp + return _tmp + end + + # Ticks4 = "````" !"`" + def _Ticks4 + + _save = self.pos + while true # sequence + _tmp = match_string("````") + unless _tmp + self.pos = _save + break + end + _save1 = self.pos + _tmp = match_string("`") + _tmp = _tmp ? nil : true + self.pos = _save1 + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_Ticks4 unless _tmp + return _tmp + end + + # Ticks5 = "`````" !"`" + def _Ticks5 + + _save = self.pos + while true # sequence + _tmp = match_string("`````") + unless _tmp + self.pos = _save + break + end + _save1 = self.pos + _tmp = match_string("`") + _tmp = _tmp ? nil : true + self.pos = _save1 + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_Ticks5 unless _tmp + return _tmp + end + + # Code = (Ticks1 @Sp < ((!"`" Nonspacechar)+ | !Ticks1 /`+/ | !(@Sp Ticks1) (@Spacechar | @Newline !@BlankLine))+ > @Sp Ticks1 | Ticks2 @Sp < ((!"`" Nonspacechar)+ | !Ticks2 /`+/ | !(@Sp Ticks2) (@Spacechar | @Newline !@BlankLine))+ > @Sp Ticks2 | Ticks3 @Sp < ((!"`" Nonspacechar)+ | !Ticks3 /`+/ | !(@Sp Ticks3) (@Spacechar | @Newline !@BlankLine))+ > @Sp Ticks3 | Ticks4 @Sp < ((!"`" Nonspacechar)+ | !Ticks4 /`+/ | !(@Sp Ticks4) (@Spacechar | @Newline !@BlankLine))+ > @Sp Ticks4 | Ticks5 @Sp < ((!"`" Nonspacechar)+ | !Ticks5 /`+/ | !(@Sp Ticks5) (@Spacechar | @Newline !@BlankLine))+ > @Sp Ticks5) { "<code>#{text}</code>" } + def _Code + + _save = self.pos + while true # sequence + + _save1 = self.pos + while true # choice + + _save2 = self.pos + while true # sequence + _tmp = apply(:_Ticks1) + unless _tmp + self.pos = _save2 + break + end + _tmp = _Sp() + unless _tmp + self.pos = _save2 + break + end + _text_start = self.pos + _save3 = self.pos + + _save4 = self.pos + while true # choice + _save5 = self.pos + + _save6 = self.pos + while true # sequence + _save7 = self.pos + _tmp = match_string("`") + _tmp = _tmp ? nil : true + self.pos = _save7 + unless _tmp + self.pos = _save6 + break + end + _tmp = apply(:_Nonspacechar) + unless _tmp + self.pos = _save6 + end + break + end # end sequence + + if _tmp + while true + + _save8 = self.pos + while true # sequence + _save9 = self.pos + _tmp = match_string("`") + _tmp = _tmp ? nil : true + self.pos = _save9 + unless _tmp + self.pos = _save8 + break + end + _tmp = apply(:_Nonspacechar) + unless _tmp + self.pos = _save8 + end + break + end # end sequence + + break unless _tmp + end + _tmp = true + else + self.pos = _save5 + end + break if _tmp + self.pos = _save4 + + _save10 = self.pos + while true # sequence + _save11 = self.pos + _tmp = apply(:_Ticks1) + _tmp = _tmp ? nil : true + self.pos = _save11 + unless _tmp + self.pos = _save10 + break + end + _tmp = scan(/\A(?-mix:`+)/) + unless _tmp + self.pos = _save10 + end + break + end # end sequence + + break if _tmp + self.pos = _save4 + + _save12 = self.pos + while true # sequence + _save13 = self.pos + + _save14 = self.pos + while true # sequence + _tmp = _Sp() + unless _tmp + self.pos = _save14 + break + end + _tmp = apply(:_Ticks1) + unless _tmp + self.pos = _save14 + end + break + end # end sequence + + _tmp = _tmp ? nil : true + self.pos = _save13 + unless _tmp + self.pos = _save12 + break + end + + _save15 = self.pos + while true # choice + _tmp = _Spacechar() + break if _tmp + self.pos = _save15 + + _save16 = self.pos + while true # sequence + _tmp = _Newline() + unless _tmp + self.pos = _save16 + break + end + _save17 = self.pos + _tmp = _BlankLine() + _tmp = _tmp ? nil : true + self.pos = _save17 + unless _tmp + self.pos = _save16 + end + break + end # end sequence + + break if _tmp + self.pos = _save15 + break + end # end choice + + unless _tmp + self.pos = _save12 + end + break + end # end sequence + + break if _tmp + self.pos = _save4 + break + end # end choice + + if _tmp + while true + + _save18 = self.pos + while true # choice + _save19 = self.pos + + _save20 = self.pos + while true # sequence + _save21 = self.pos + _tmp = match_string("`") + _tmp = _tmp ? nil : true + self.pos = _save21 + unless _tmp + self.pos = _save20 + break + end + _tmp = apply(:_Nonspacechar) + unless _tmp + self.pos = _save20 + end + break + end # end sequence + + if _tmp + while true + + _save22 = self.pos + while true # sequence + _save23 = self.pos + _tmp = match_string("`") + _tmp = _tmp ? nil : true + self.pos = _save23 + unless _tmp + self.pos = _save22 + break + end + _tmp = apply(:_Nonspacechar) + unless _tmp + self.pos = _save22 + end + break + end # end sequence + + break unless _tmp + end + _tmp = true + else + self.pos = _save19 + end + break if _tmp + self.pos = _save18 + + _save24 = self.pos + while true # sequence + _save25 = self.pos + _tmp = apply(:_Ticks1) + _tmp = _tmp ? nil : true + self.pos = _save25 + unless _tmp + self.pos = _save24 + break + end + _tmp = scan(/\A(?-mix:`+)/) + unless _tmp + self.pos = _save24 + end + break + end # end sequence + + break if _tmp + self.pos = _save18 + + _save26 = self.pos + while true # sequence + _save27 = self.pos + + _save28 = self.pos + while true # sequence + _tmp = _Sp() + unless _tmp + self.pos = _save28 + break + end + _tmp = apply(:_Ticks1) + unless _tmp + self.pos = _save28 + end + break + end # end sequence + + _tmp = _tmp ? nil : true + self.pos = _save27 + unless _tmp + self.pos = _save26 + break + end + + _save29 = self.pos + while true # choice + _tmp = _Spacechar() + break if _tmp + self.pos = _save29 + + _save30 = self.pos + while true # sequence + _tmp = _Newline() + unless _tmp + self.pos = _save30 + break + end + _save31 = self.pos + _tmp = _BlankLine() + _tmp = _tmp ? nil : true + self.pos = _save31 + unless _tmp + self.pos = _save30 + end + break + end # end sequence + + break if _tmp + self.pos = _save29 + break + end # end choice + + unless _tmp + self.pos = _save26 + end + break + end # end sequence + + break if _tmp + self.pos = _save18 + break + end # end choice + + break unless _tmp + end + _tmp = true + else + self.pos = _save3 + end + if _tmp + text = get_text(_text_start) + end + unless _tmp + self.pos = _save2 + break + end + _tmp = _Sp() + unless _tmp + self.pos = _save2 + break + end + _tmp = apply(:_Ticks1) + unless _tmp + self.pos = _save2 + end + break + end # end sequence + + break if _tmp + self.pos = _save1 + + _save32 = self.pos + while true # sequence + _tmp = apply(:_Ticks2) + unless _tmp + self.pos = _save32 + break + end + _tmp = _Sp() + unless _tmp + self.pos = _save32 + break + end + _text_start = self.pos + _save33 = self.pos + + _save34 = self.pos + while true # choice + _save35 = self.pos + + _save36 = self.pos + while true # sequence + _save37 = self.pos + _tmp = match_string("`") + _tmp = _tmp ? nil : true + self.pos = _save37 + unless _tmp + self.pos = _save36 + break + end + _tmp = apply(:_Nonspacechar) + unless _tmp + self.pos = _save36 + end + break + end # end sequence + + if _tmp + while true + + _save38 = self.pos + while true # sequence + _save39 = self.pos + _tmp = match_string("`") + _tmp = _tmp ? nil : true + self.pos = _save39 + unless _tmp + self.pos = _save38 + break + end + _tmp = apply(:_Nonspacechar) + unless _tmp + self.pos = _save38 + end + break + end # end sequence + + break unless _tmp + end + _tmp = true + else + self.pos = _save35 + end + break if _tmp + self.pos = _save34 + + _save40 = self.pos + while true # sequence + _save41 = self.pos + _tmp = apply(:_Ticks2) + _tmp = _tmp ? nil : true + self.pos = _save41 + unless _tmp + self.pos = _save40 + break + end + _tmp = scan(/\A(?-mix:`+)/) + unless _tmp + self.pos = _save40 + end + break + end # end sequence + + break if _tmp + self.pos = _save34 + + _save42 = self.pos + while true # sequence + _save43 = self.pos + + _save44 = self.pos + while true # sequence + _tmp = _Sp() + unless _tmp + self.pos = _save44 + break + end + _tmp = apply(:_Ticks2) + unless _tmp + self.pos = _save44 + end + break + end # end sequence + + _tmp = _tmp ? nil : true + self.pos = _save43 + unless _tmp + self.pos = _save42 + break + end + + _save45 = self.pos + while true # choice + _tmp = _Spacechar() + break if _tmp + self.pos = _save45 + + _save46 = self.pos + while true # sequence + _tmp = _Newline() + unless _tmp + self.pos = _save46 + break + end + _save47 = self.pos + _tmp = _BlankLine() + _tmp = _tmp ? nil : true + self.pos = _save47 + unless _tmp + self.pos = _save46 + end + break + end # end sequence + + break if _tmp + self.pos = _save45 + break + end # end choice + + unless _tmp + self.pos = _save42 + end + break + end # end sequence + + break if _tmp + self.pos = _save34 + break + end # end choice + + if _tmp + while true + + _save48 = self.pos + while true # choice + _save49 = self.pos + + _save50 = self.pos + while true # sequence + _save51 = self.pos + _tmp = match_string("`") + _tmp = _tmp ? nil : true + self.pos = _save51 + unless _tmp + self.pos = _save50 + break + end + _tmp = apply(:_Nonspacechar) + unless _tmp + self.pos = _save50 + end + break + end # end sequence + + if _tmp + while true + + _save52 = self.pos + while true # sequence + _save53 = self.pos + _tmp = match_string("`") + _tmp = _tmp ? nil : true + self.pos = _save53 + unless _tmp + self.pos = _save52 + break + end + _tmp = apply(:_Nonspacechar) + unless _tmp + self.pos = _save52 + end + break + end # end sequence + + break unless _tmp + end + _tmp = true + else + self.pos = _save49 + end + break if _tmp + self.pos = _save48 + + _save54 = self.pos + while true # sequence + _save55 = self.pos + _tmp = apply(:_Ticks2) + _tmp = _tmp ? nil : true + self.pos = _save55 + unless _tmp + self.pos = _save54 + break + end + _tmp = scan(/\A(?-mix:`+)/) + unless _tmp + self.pos = _save54 + end + break + end # end sequence + + break if _tmp + self.pos = _save48 + + _save56 = self.pos + while true # sequence + _save57 = self.pos + + _save58 = self.pos + while true # sequence + _tmp = _Sp() + unless _tmp + self.pos = _save58 + break + end + _tmp = apply(:_Ticks2) + unless _tmp + self.pos = _save58 + end + break + end # end sequence + + _tmp = _tmp ? nil : true + self.pos = _save57 + unless _tmp + self.pos = _save56 + break + end + + _save59 = self.pos + while true # choice + _tmp = _Spacechar() + break if _tmp + self.pos = _save59 + + _save60 = self.pos + while true # sequence + _tmp = _Newline() + unless _tmp + self.pos = _save60 + break + end + _save61 = self.pos + _tmp = _BlankLine() + _tmp = _tmp ? nil : true + self.pos = _save61 + unless _tmp + self.pos = _save60 + end + break + end # end sequence + + break if _tmp + self.pos = _save59 + break + end # end choice + + unless _tmp + self.pos = _save56 + end + break + end # end sequence + + break if _tmp + self.pos = _save48 + break + end # end choice + + break unless _tmp + end + _tmp = true + else + self.pos = _save33 + end + if _tmp + text = get_text(_text_start) + end + unless _tmp + self.pos = _save32 + break + end + _tmp = _Sp() + unless _tmp + self.pos = _save32 + break + end + _tmp = apply(:_Ticks2) + unless _tmp + self.pos = _save32 + end + break + end # end sequence + + break if _tmp + self.pos = _save1 + + _save62 = self.pos + while true # sequence + _tmp = apply(:_Ticks3) + unless _tmp + self.pos = _save62 + break + end + _tmp = _Sp() + unless _tmp + self.pos = _save62 + break + end + _text_start = self.pos + _save63 = self.pos + + _save64 = self.pos + while true # choice + _save65 = self.pos + + _save66 = self.pos + while true # sequence + _save67 = self.pos + _tmp = match_string("`") + _tmp = _tmp ? nil : true + self.pos = _save67 + unless _tmp + self.pos = _save66 + break + end + _tmp = apply(:_Nonspacechar) + unless _tmp + self.pos = _save66 + end + break + end # end sequence + + if _tmp + while true + + _save68 = self.pos + while true # sequence + _save69 = self.pos + _tmp = match_string("`") + _tmp = _tmp ? nil : true + self.pos = _save69 + unless _tmp + self.pos = _save68 + break + end + _tmp = apply(:_Nonspacechar) + unless _tmp + self.pos = _save68 + end + break + end # end sequence + + break unless _tmp + end + _tmp = true + else + self.pos = _save65 + end + break if _tmp + self.pos = _save64 + + _save70 = self.pos + while true # sequence + _save71 = self.pos + _tmp = apply(:_Ticks3) + _tmp = _tmp ? nil : true + self.pos = _save71 + unless _tmp + self.pos = _save70 + break + end + _tmp = scan(/\A(?-mix:`+)/) + unless _tmp + self.pos = _save70 + end + break + end # end sequence + + break if _tmp + self.pos = _save64 + + _save72 = self.pos + while true # sequence + _save73 = self.pos + + _save74 = self.pos + while true # sequence + _tmp = _Sp() + unless _tmp + self.pos = _save74 + break + end + _tmp = apply(:_Ticks3) + unless _tmp + self.pos = _save74 + end + break + end # end sequence + + _tmp = _tmp ? nil : true + self.pos = _save73 + unless _tmp + self.pos = _save72 + break + end + + _save75 = self.pos + while true # choice + _tmp = _Spacechar() + break if _tmp + self.pos = _save75 + + _save76 = self.pos + while true # sequence + _tmp = _Newline() + unless _tmp + self.pos = _save76 + break + end + _save77 = self.pos + _tmp = _BlankLine() + _tmp = _tmp ? nil : true + self.pos = _save77 + unless _tmp + self.pos = _save76 + end + break + end # end sequence + + break if _tmp + self.pos = _save75 + break + end # end choice + + unless _tmp + self.pos = _save72 + end + break + end # end sequence + + break if _tmp + self.pos = _save64 + break + end # end choice + + if _tmp + while true + + _save78 = self.pos + while true # choice + _save79 = self.pos + + _save80 = self.pos + while true # sequence + _save81 = self.pos + _tmp = match_string("`") + _tmp = _tmp ? nil : true + self.pos = _save81 + unless _tmp + self.pos = _save80 + break + end + _tmp = apply(:_Nonspacechar) + unless _tmp + self.pos = _save80 + end + break + end # end sequence + + if _tmp + while true + + _save82 = self.pos + while true # sequence + _save83 = self.pos + _tmp = match_string("`") + _tmp = _tmp ? nil : true + self.pos = _save83 + unless _tmp + self.pos = _save82 + break + end + _tmp = apply(:_Nonspacechar) + unless _tmp + self.pos = _save82 + end + break + end # end sequence + + break unless _tmp + end + _tmp = true + else + self.pos = _save79 + end + break if _tmp + self.pos = _save78 + + _save84 = self.pos + while true # sequence + _save85 = self.pos + _tmp = apply(:_Ticks3) + _tmp = _tmp ? nil : true + self.pos = _save85 + unless _tmp + self.pos = _save84 + break + end + _tmp = scan(/\A(?-mix:`+)/) + unless _tmp + self.pos = _save84 + end + break + end # end sequence + + break if _tmp + self.pos = _save78 + + _save86 = self.pos + while true # sequence + _save87 = self.pos + + _save88 = self.pos + while true # sequence + _tmp = _Sp() + unless _tmp + self.pos = _save88 + break + end + _tmp = apply(:_Ticks3) + unless _tmp + self.pos = _save88 + end + break + end # end sequence + + _tmp = _tmp ? nil : true + self.pos = _save87 + unless _tmp + self.pos = _save86 + break + end + + _save89 = self.pos + while true # choice + _tmp = _Spacechar() + break if _tmp + self.pos = _save89 + + _save90 = self.pos + while true # sequence + _tmp = _Newline() + unless _tmp + self.pos = _save90 + break + end + _save91 = self.pos + _tmp = _BlankLine() + _tmp = _tmp ? nil : true + self.pos = _save91 + unless _tmp + self.pos = _save90 + end + break + end # end sequence + + break if _tmp + self.pos = _save89 + break + end # end choice + + unless _tmp + self.pos = _save86 + end + break + end # end sequence + + break if _tmp + self.pos = _save78 + break + end # end choice + + break unless _tmp + end + _tmp = true + else + self.pos = _save63 + end + if _tmp + text = get_text(_text_start) + end + unless _tmp + self.pos = _save62 + break + end + _tmp = _Sp() + unless _tmp + self.pos = _save62 + break + end + _tmp = apply(:_Ticks3) + unless _tmp + self.pos = _save62 + end + break + end # end sequence + + break if _tmp + self.pos = _save1 + + _save92 = self.pos + while true # sequence + _tmp = apply(:_Ticks4) + unless _tmp + self.pos = _save92 + break + end + _tmp = _Sp() + unless _tmp + self.pos = _save92 + break + end + _text_start = self.pos + _save93 = self.pos + + _save94 = self.pos + while true # choice + _save95 = self.pos + + _save96 = self.pos + while true # sequence + _save97 = self.pos + _tmp = match_string("`") + _tmp = _tmp ? nil : true + self.pos = _save97 + unless _tmp + self.pos = _save96 + break + end + _tmp = apply(:_Nonspacechar) + unless _tmp + self.pos = _save96 + end + break + end # end sequence + + if _tmp + while true + + _save98 = self.pos + while true # sequence + _save99 = self.pos + _tmp = match_string("`") + _tmp = _tmp ? nil : true + self.pos = _save99 + unless _tmp + self.pos = _save98 + break + end + _tmp = apply(:_Nonspacechar) + unless _tmp + self.pos = _save98 + end + break + end # end sequence + + break unless _tmp + end + _tmp = true + else + self.pos = _save95 + end + break if _tmp + self.pos = _save94 + + _save100 = self.pos + while true # sequence + _save101 = self.pos + _tmp = apply(:_Ticks4) + _tmp = _tmp ? nil : true + self.pos = _save101 + unless _tmp + self.pos = _save100 + break + end + _tmp = scan(/\A(?-mix:`+)/) + unless _tmp + self.pos = _save100 + end + break + end # end sequence + + break if _tmp + self.pos = _save94 + + _save102 = self.pos + while true # sequence + _save103 = self.pos + + _save104 = self.pos + while true # sequence + _tmp = _Sp() + unless _tmp + self.pos = _save104 + break + end + _tmp = apply(:_Ticks4) + unless _tmp + self.pos = _save104 + end + break + end # end sequence + + _tmp = _tmp ? nil : true + self.pos = _save103 + unless _tmp + self.pos = _save102 + break + end + + _save105 = self.pos + while true # choice + _tmp = _Spacechar() + break if _tmp + self.pos = _save105 + + _save106 = self.pos + while true # sequence + _tmp = _Newline() + unless _tmp + self.pos = _save106 + break + end + _save107 = self.pos + _tmp = _BlankLine() + _tmp = _tmp ? nil : true + self.pos = _save107 + unless _tmp + self.pos = _save106 + end + break + end # end sequence + + break if _tmp + self.pos = _save105 + break + end # end choice + + unless _tmp + self.pos = _save102 + end + break + end # end sequence + + break if _tmp + self.pos = _save94 + break + end # end choice + + if _tmp + while true + + _save108 = self.pos + while true # choice + _save109 = self.pos + + _save110 = self.pos + while true # sequence + _save111 = self.pos + _tmp = match_string("`") + _tmp = _tmp ? nil : true + self.pos = _save111 + unless _tmp + self.pos = _save110 + break + end + _tmp = apply(:_Nonspacechar) + unless _tmp + self.pos = _save110 + end + break + end # end sequence + + if _tmp + while true + + _save112 = self.pos + while true # sequence + _save113 = self.pos + _tmp = match_string("`") + _tmp = _tmp ? nil : true + self.pos = _save113 + unless _tmp + self.pos = _save112 + break + end + _tmp = apply(:_Nonspacechar) + unless _tmp + self.pos = _save112 + end + break + end # end sequence + + break unless _tmp + end + _tmp = true + else + self.pos = _save109 + end + break if _tmp + self.pos = _save108 + + _save114 = self.pos + while true # sequence + _save115 = self.pos + _tmp = apply(:_Ticks4) + _tmp = _tmp ? nil : true + self.pos = _save115 + unless _tmp + self.pos = _save114 + break + end + _tmp = scan(/\A(?-mix:`+)/) + unless _tmp + self.pos = _save114 + end + break + end # end sequence + + break if _tmp + self.pos = _save108 + + _save116 = self.pos + while true # sequence + _save117 = self.pos + + _save118 = self.pos + while true # sequence + _tmp = _Sp() + unless _tmp + self.pos = _save118 + break + end + _tmp = apply(:_Ticks4) + unless _tmp + self.pos = _save118 + end + break + end # end sequence + + _tmp = _tmp ? nil : true + self.pos = _save117 + unless _tmp + self.pos = _save116 + break + end + + _save119 = self.pos + while true # choice + _tmp = _Spacechar() + break if _tmp + self.pos = _save119 + + _save120 = self.pos + while true # sequence + _tmp = _Newline() + unless _tmp + self.pos = _save120 + break + end + _save121 = self.pos + _tmp = _BlankLine() + _tmp = _tmp ? nil : true + self.pos = _save121 + unless _tmp + self.pos = _save120 + end + break + end # end sequence + + break if _tmp + self.pos = _save119 + break + end # end choice + + unless _tmp + self.pos = _save116 + end + break + end # end sequence + + break if _tmp + self.pos = _save108 + break + end # end choice + + break unless _tmp + end + _tmp = true + else + self.pos = _save93 + end + if _tmp + text = get_text(_text_start) + end + unless _tmp + self.pos = _save92 + break + end + _tmp = _Sp() + unless _tmp + self.pos = _save92 + break + end + _tmp = apply(:_Ticks4) + unless _tmp + self.pos = _save92 + end + break + end # end sequence + + break if _tmp + self.pos = _save1 + + _save122 = self.pos + while true # sequence + _tmp = apply(:_Ticks5) + unless _tmp + self.pos = _save122 + break + end + _tmp = _Sp() + unless _tmp + self.pos = _save122 + break + end + _text_start = self.pos + _save123 = self.pos + + _save124 = self.pos + while true # choice + _save125 = self.pos + + _save126 = self.pos + while true # sequence + _save127 = self.pos + _tmp = match_string("`") + _tmp = _tmp ? nil : true + self.pos = _save127 + unless _tmp + self.pos = _save126 + break + end + _tmp = apply(:_Nonspacechar) + unless _tmp + self.pos = _save126 + end + break + end # end sequence + + if _tmp + while true + + _save128 = self.pos + while true # sequence + _save129 = self.pos + _tmp = match_string("`") + _tmp = _tmp ? nil : true + self.pos = _save129 + unless _tmp + self.pos = _save128 + break + end + _tmp = apply(:_Nonspacechar) + unless _tmp + self.pos = _save128 + end + break + end # end sequence + + break unless _tmp + end + _tmp = true + else + self.pos = _save125 + end + break if _tmp + self.pos = _save124 + + _save130 = self.pos + while true # sequence + _save131 = self.pos + _tmp = apply(:_Ticks5) + _tmp = _tmp ? nil : true + self.pos = _save131 + unless _tmp + self.pos = _save130 + break + end + _tmp = scan(/\A(?-mix:`+)/) + unless _tmp + self.pos = _save130 + end + break + end # end sequence + + break if _tmp + self.pos = _save124 + + _save132 = self.pos + while true # sequence + _save133 = self.pos + + _save134 = self.pos + while true # sequence + _tmp = _Sp() + unless _tmp + self.pos = _save134 + break + end + _tmp = apply(:_Ticks5) + unless _tmp + self.pos = _save134 + end + break + end # end sequence + + _tmp = _tmp ? nil : true + self.pos = _save133 + unless _tmp + self.pos = _save132 + break + end + + _save135 = self.pos + while true # choice + _tmp = _Spacechar() + break if _tmp + self.pos = _save135 + + _save136 = self.pos + while true # sequence + _tmp = _Newline() + unless _tmp + self.pos = _save136 + break + end + _save137 = self.pos + _tmp = _BlankLine() + _tmp = _tmp ? nil : true + self.pos = _save137 + unless _tmp + self.pos = _save136 + end + break + end # end sequence + + break if _tmp + self.pos = _save135 + break + end # end choice + + unless _tmp + self.pos = _save132 + end + break + end # end sequence + + break if _tmp + self.pos = _save124 + break + end # end choice + + if _tmp + while true + + _save138 = self.pos + while true # choice + _save139 = self.pos + + _save140 = self.pos + while true # sequence + _save141 = self.pos + _tmp = match_string("`") + _tmp = _tmp ? nil : true + self.pos = _save141 + unless _tmp + self.pos = _save140 + break + end + _tmp = apply(:_Nonspacechar) + unless _tmp + self.pos = _save140 + end + break + end # end sequence + + if _tmp + while true + + _save142 = self.pos + while true # sequence + _save143 = self.pos + _tmp = match_string("`") + _tmp = _tmp ? nil : true + self.pos = _save143 + unless _tmp + self.pos = _save142 + break + end + _tmp = apply(:_Nonspacechar) + unless _tmp + self.pos = _save142 + end + break + end # end sequence + + break unless _tmp + end + _tmp = true + else + self.pos = _save139 + end + break if _tmp + self.pos = _save138 + + _save144 = self.pos + while true # sequence + _save145 = self.pos + _tmp = apply(:_Ticks5) + _tmp = _tmp ? nil : true + self.pos = _save145 + unless _tmp + self.pos = _save144 + break + end + _tmp = scan(/\A(?-mix:`+)/) + unless _tmp + self.pos = _save144 + end + break + end # end sequence + + break if _tmp + self.pos = _save138 + + _save146 = self.pos + while true # sequence + _save147 = self.pos + + _save148 = self.pos + while true # sequence + _tmp = _Sp() + unless _tmp + self.pos = _save148 + break + end + _tmp = apply(:_Ticks5) + unless _tmp + self.pos = _save148 + end + break + end # end sequence + + _tmp = _tmp ? nil : true + self.pos = _save147 + unless _tmp + self.pos = _save146 + break + end + + _save149 = self.pos + while true # choice + _tmp = _Spacechar() + break if _tmp + self.pos = _save149 + + _save150 = self.pos + while true # sequence + _tmp = _Newline() + unless _tmp + self.pos = _save150 + break + end + _save151 = self.pos + _tmp = _BlankLine() + _tmp = _tmp ? nil : true + self.pos = _save151 + unless _tmp + self.pos = _save150 + end + break + end # end sequence + + break if _tmp + self.pos = _save149 + break + end # end choice + + unless _tmp + self.pos = _save146 + end + break + end # end sequence + + break if _tmp + self.pos = _save138 + break + end # end choice + + break unless _tmp + end + _tmp = true + else + self.pos = _save123 + end + if _tmp + text = get_text(_text_start) + end + unless _tmp + self.pos = _save122 + break + end + _tmp = _Sp() + unless _tmp + self.pos = _save122 + break + end + _tmp = apply(:_Ticks5) + unless _tmp + self.pos = _save122 + end + break + end # end sequence + + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + @result = begin; "<code>#{text}</code>" ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_Code unless _tmp + return _tmp + end + + # RawHtml = < (HtmlComment | HtmlBlockScript | HtmlTag) > { if html? then text else '' end } + def _RawHtml + + _save = self.pos + while true # sequence + _text_start = self.pos + + _save1 = self.pos + while true # choice + _tmp = apply(:_HtmlComment) + break if _tmp + self.pos = _save1 + _tmp = apply(:_HtmlBlockScript) + break if _tmp + self.pos = _save1 + _tmp = apply(:_HtmlTag) + break if _tmp + self.pos = _save1 + break + end # end choice + + if _tmp + text = get_text(_text_start) + end + unless _tmp + self.pos = _save + break + end + @result = begin; if html? then text else '' end ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_RawHtml unless _tmp + return _tmp + end + + # BlankLine = @Sp @Newline { "\n" } + def _BlankLine + + _save = self.pos + while true # sequence + _tmp = _Sp() + unless _tmp + self.pos = _save + break + end + _tmp = _Newline() + unless _tmp + self.pos = _save + break + end + @result = begin; "\n" ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_BlankLine unless _tmp + return _tmp + end + + # Quoted = ("\"" (!"\"" .)* "\"" | "'" (!"'" .)* "'") + def _Quoted + + _save = self.pos + while true # choice + + _save1 = self.pos + while true # sequence + _tmp = match_string("\"") + unless _tmp + self.pos = _save1 + break + end + while true + + _save3 = self.pos + while true # sequence + _save4 = self.pos + _tmp = match_string("\"") + _tmp = _tmp ? nil : true + self.pos = _save4 + unless _tmp + self.pos = _save3 + break + end + _tmp = get_byte + unless _tmp + self.pos = _save3 + end + break + end # end sequence + + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save1 + break + end + _tmp = match_string("\"") + unless _tmp + self.pos = _save1 + end + break + end # end sequence + + break if _tmp + self.pos = _save + + _save5 = self.pos + while true # sequence + _tmp = match_string("'") + unless _tmp + self.pos = _save5 + break + end + while true + + _save7 = self.pos + while true # sequence + _save8 = self.pos + _tmp = match_string("'") + _tmp = _tmp ? nil : true + self.pos = _save8 + unless _tmp + self.pos = _save7 + break + end + _tmp = get_byte + unless _tmp + self.pos = _save7 + end + break + end # end sequence + + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save5 + break + end + _tmp = match_string("'") + unless _tmp + self.pos = _save5 + end + break + end # end sequence + + break if _tmp + self.pos = _save + break + end # end choice + + set_failed_rule :_Quoted unless _tmp + return _tmp + end + + # HtmlAttribute = (AlphanumericAscii | "-")+ Spnl ("=" Spnl (Quoted | (!">" Nonspacechar)+))? Spnl + def _HtmlAttribute + + _save = self.pos + while true # sequence + _save1 = self.pos + + _save2 = self.pos + while true # choice + _tmp = apply(:_AlphanumericAscii) + break if _tmp + self.pos = _save2 + _tmp = match_string("-") + break if _tmp + self.pos = _save2 + break + end # end choice + + if _tmp + while true + + _save3 = self.pos + while true # choice + _tmp = apply(:_AlphanumericAscii) + break if _tmp + self.pos = _save3 + _tmp = match_string("-") + break if _tmp + self.pos = _save3 + break + end # end choice + + break unless _tmp + end + _tmp = true + else + self.pos = _save1 + end + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _save4 = self.pos + + _save5 = self.pos + while true # sequence + _tmp = match_string("=") + unless _tmp + self.pos = _save5 + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save5 + break + end + + _save6 = self.pos + while true # choice + _tmp = apply(:_Quoted) + break if _tmp + self.pos = _save6 + _save7 = self.pos + + _save8 = self.pos + while true # sequence + _save9 = self.pos + _tmp = match_string(">") + _tmp = _tmp ? nil : true + self.pos = _save9 + unless _tmp + self.pos = _save8 + break + end + _tmp = apply(:_Nonspacechar) + unless _tmp + self.pos = _save8 + end + break + end # end sequence + + if _tmp + while true + + _save10 = self.pos + while true # sequence + _save11 = self.pos + _tmp = match_string(">") + _tmp = _tmp ? nil : true + self.pos = _save11 + unless _tmp + self.pos = _save10 + break + end + _tmp = apply(:_Nonspacechar) + unless _tmp + self.pos = _save10 + end + break + end # end sequence + + break unless _tmp + end + _tmp = true + else + self.pos = _save7 + end + break if _tmp + self.pos = _save6 + break + end # end choice + + unless _tmp + self.pos = _save5 + end + break + end # end sequence + + unless _tmp + _tmp = true + self.pos = _save4 + end + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlAttribute unless _tmp + return _tmp + end + + # HtmlComment = "<!--" (!"-->" .)* "-->" + def _HtmlComment + + _save = self.pos + while true # sequence + _tmp = match_string("<!--") + unless _tmp + self.pos = _save + break + end + while true + + _save2 = self.pos + while true # sequence + _save3 = self.pos + _tmp = match_string("-->") + _tmp = _tmp ? nil : true + self.pos = _save3 + unless _tmp + self.pos = _save2 + break + end + _tmp = get_byte + unless _tmp + self.pos = _save2 + end + break + end # end sequence + + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _tmp = match_string("-->") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlComment unless _tmp + return _tmp + end + + # HtmlTag = "<" Spnl "/"? AlphanumericAscii+ Spnl HtmlAttribute* "/"? Spnl ">" + def _HtmlTag + + _save = self.pos + while true # sequence + _tmp = match_string("<") + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _save1 = self.pos + _tmp = match_string("/") + unless _tmp + _tmp = true + self.pos = _save1 + end + unless _tmp + self.pos = _save + break + end + _save2 = self.pos + _tmp = apply(:_AlphanumericAscii) + if _tmp + while true + _tmp = apply(:_AlphanumericAscii) + break unless _tmp + end + _tmp = true + else + self.pos = _save2 + end + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + while true + _tmp = apply(:_HtmlAttribute) + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + _save4 = self.pos + _tmp = match_string("/") + unless _tmp + _tmp = true + self.pos = _save4 + end + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _tmp = match_string(">") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HtmlTag unless _tmp + return _tmp + end + + # Eof = !. + def _Eof + _save = self.pos + _tmp = get_byte + _tmp = _tmp ? nil : true + self.pos = _save + set_failed_rule :_Eof unless _tmp + return _tmp + end + + # Nonspacechar = !@Spacechar !@Newline . + def _Nonspacechar + + _save = self.pos + while true # sequence + _save1 = self.pos + _tmp = _Spacechar() + _tmp = _tmp ? nil : true + self.pos = _save1 + unless _tmp + self.pos = _save + break + end + _save2 = self.pos + _tmp = _Newline() + _tmp = _tmp ? nil : true + self.pos = _save2 + unless _tmp + self.pos = _save + break + end + _tmp = get_byte + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_Nonspacechar unless _tmp + return _tmp + end + + # Sp = @Spacechar* + def _Sp + while true + _tmp = _Spacechar() + break unless _tmp + end + _tmp = true + set_failed_rule :_Sp unless _tmp + return _tmp + end + + # Spnl = @Sp (@Newline @Sp)? + def _Spnl + + _save = self.pos + while true # sequence + _tmp = _Sp() + unless _tmp + self.pos = _save + break + end + _save1 = self.pos + + _save2 = self.pos + while true # sequence + _tmp = _Newline() + unless _tmp + self.pos = _save2 + break + end + _tmp = _Sp() + unless _tmp + self.pos = _save2 + end + break + end # end sequence + + unless _tmp + _tmp = true + self.pos = _save1 + end + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_Spnl unless _tmp + return _tmp + end + + # SpecialChar = (/[*_`&\[\]()<!#\\'"]/ | @ExtendedSpecialChar) + def _SpecialChar + + _save = self.pos + while true # choice + _tmp = scan(/\A(?-mix:[*_`&\[\]()<!#\\'"])/) + break if _tmp + self.pos = _save + _tmp = _ExtendedSpecialChar() + break if _tmp + self.pos = _save + break + end # end choice + + set_failed_rule :_SpecialChar unless _tmp + return _tmp + end + + # NormalChar = !(@SpecialChar | @Spacechar | @Newline) . + def _NormalChar + + _save = self.pos + while true # sequence + _save1 = self.pos + + _save2 = self.pos + while true # choice + _tmp = _SpecialChar() + break if _tmp + self.pos = _save2 + _tmp = _Spacechar() + break if _tmp + self.pos = _save2 + _tmp = _Newline() + break if _tmp + self.pos = _save2 + break + end # end choice + + _tmp = _tmp ? nil : true + self.pos = _save1 + unless _tmp + self.pos = _save + break + end + _tmp = get_byte + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_NormalChar unless _tmp + return _tmp + end + + # Digit = [0-9] + def _Digit + _save = self.pos + _tmp = get_byte + if _tmp + unless _tmp >= 48 and _tmp <= 57 + self.pos = _save + _tmp = nil + end + end + set_failed_rule :_Digit unless _tmp + return _tmp + end + + # Alphanumeric = %literals.Alphanumeric + def _Alphanumeric + _tmp = @_grammar_literals.external_invoke(self, :_Alphanumeric) + set_failed_rule :_Alphanumeric unless _tmp + return _tmp + end + + # AlphanumericAscii = %literals.AlphanumericAscii + def _AlphanumericAscii + _tmp = @_grammar_literals.external_invoke(self, :_AlphanumericAscii) + set_failed_rule :_AlphanumericAscii unless _tmp + return _tmp + end + + # BOM = %literals.BOM + def _BOM + _tmp = @_grammar_literals.external_invoke(self, :_BOM) + set_failed_rule :_BOM unless _tmp + return _tmp + end + + # Newline = %literals.Newline + def _Newline + _tmp = @_grammar_literals.external_invoke(self, :_Newline) + set_failed_rule :_Newline unless _tmp + return _tmp + end + + # NonAlphanumeric = %literals.NonAlphanumeric + def _NonAlphanumeric + _tmp = @_grammar_literals.external_invoke(self, :_NonAlphanumeric) + set_failed_rule :_NonAlphanumeric unless _tmp + return _tmp + end + + # Spacechar = %literals.Spacechar + def _Spacechar + _tmp = @_grammar_literals.external_invoke(self, :_Spacechar) + set_failed_rule :_Spacechar unless _tmp + return _tmp + end + + # HexEntity = /&#x/i < /[0-9a-fA-F]+/ > ";" { [text.to_i(16)].pack 'U' } + def _HexEntity + + _save = self.pos + while true # sequence + _tmp = scan(/\A(?i-mx:&#x)/) + unless _tmp + self.pos = _save + break + end + _text_start = self.pos + _tmp = scan(/\A(?-mix:[0-9a-fA-F]+)/) + if _tmp + text = get_text(_text_start) + end + unless _tmp + self.pos = _save + break + end + _tmp = match_string(";") + unless _tmp + self.pos = _save + break + end + @result = begin; [text.to_i(16)].pack 'U' ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_HexEntity unless _tmp + return _tmp + end + + # DecEntity = "&#" < /[0-9]+/ > ";" { [text.to_i].pack 'U' } + def _DecEntity + + _save = self.pos + while true # sequence + _tmp = match_string("&#") + unless _tmp + self.pos = _save + break + end + _text_start = self.pos + _tmp = scan(/\A(?-mix:[0-9]+)/) + if _tmp + text = get_text(_text_start) + end + unless _tmp + self.pos = _save + break + end + _tmp = match_string(";") + unless _tmp + self.pos = _save + break + end + @result = begin; [text.to_i].pack 'U' ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_DecEntity unless _tmp + return _tmp + end + + # CharEntity = "&" < /[A-Za-z0-9]+/ > ";" { if entity = HTML_ENTITIES[text] then entity.pack 'U*' else "&#{text};" end } + def _CharEntity + + _save = self.pos + while true # sequence + _tmp = match_string("&") + unless _tmp + self.pos = _save + break + end + _text_start = self.pos + _tmp = scan(/\A(?-mix:[A-Za-z0-9]+)/) + if _tmp + text = get_text(_text_start) + end + unless _tmp + self.pos = _save + break + end + _tmp = match_string(";") + unless _tmp + self.pos = _save + break + end + @result = begin; if entity = HTML_ENTITIES[text] then + entity.pack 'U*' + else + "&#{text};" + end + ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_CharEntity unless _tmp + return _tmp + end + + # NonindentSpace = / {0,3}/ + def _NonindentSpace + _tmp = scan(/\A(?-mix: {0,3})/) + set_failed_rule :_NonindentSpace unless _tmp + return _tmp + end + + # Indent = /\t| / + def _Indent + _tmp = scan(/\A(?-mix:\t| )/) + set_failed_rule :_Indent unless _tmp + return _tmp + end + + # IndentedLine = Indent Line + def _IndentedLine + + _save = self.pos + while true # sequence + _tmp = apply(:_Indent) + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Line) + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_IndentedLine unless _tmp + return _tmp + end + + # OptionallyIndentedLine = Indent? Line + def _OptionallyIndentedLine + + _save = self.pos + while true # sequence + _save1 = self.pos + _tmp = apply(:_Indent) + unless _tmp + _tmp = true + self.pos = _save1 + end + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Line) + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_OptionallyIndentedLine unless _tmp + return _tmp + end + + # StartList = &. { [] } + def _StartList + + _save = self.pos + while true # sequence + _save1 = self.pos + _tmp = get_byte + self.pos = _save1 + unless _tmp + self.pos = _save + break + end + @result = begin; [] ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_StartList unless _tmp + return _tmp + end + + # Line = @RawLine:a { a } + def _Line + + _save = self.pos + while true # sequence + _tmp = _RawLine() + a = @result + unless _tmp + self.pos = _save + break + end + @result = begin; a ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_Line unless _tmp + return _tmp + end + + # RawLine = (< (!"\r" !"\n" .)* @Newline > | < .+ > @Eof) { text } + def _RawLine + + _save = self.pos + while true # sequence + + _save1 = self.pos + while true # choice + _text_start = self.pos + + _save2 = self.pos + while true # sequence + while true + + _save4 = self.pos + while true # sequence + _save5 = self.pos + _tmp = match_string("\r") + _tmp = _tmp ? nil : true + self.pos = _save5 + unless _tmp + self.pos = _save4 + break + end + _save6 = self.pos + _tmp = match_string("\n") + _tmp = _tmp ? nil : true + self.pos = _save6 + unless _tmp + self.pos = _save4 + break + end + _tmp = get_byte + unless _tmp + self.pos = _save4 + end + break + end # end sequence + + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save2 + break + end + _tmp = _Newline() + unless _tmp + self.pos = _save2 + end + break + end # end sequence + + if _tmp + text = get_text(_text_start) + end + break if _tmp + self.pos = _save1 + + _save7 = self.pos + while true # sequence + _text_start = self.pos + _save8 = self.pos + _tmp = get_byte + if _tmp + while true + _tmp = get_byte + break unless _tmp + end + _tmp = true + else + self.pos = _save8 + end + if _tmp + text = get_text(_text_start) + end + unless _tmp + self.pos = _save7 + break + end + _tmp = _Eof() + unless _tmp + self.pos = _save7 + end + break + end # end sequence + + break if _tmp + self.pos = _save1 + break + end # end choice + + unless _tmp + self.pos = _save + break + end + @result = begin; text ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_RawLine unless _tmp + return _tmp + end + + # SkipBlock = (HtmlBlock | (!"#" !SetextBottom1 !SetextBottom2 !@BlankLine @RawLine)+ @BlankLine* | @BlankLine+ | @RawLine) + def _SkipBlock + + _save = self.pos + while true # choice + _tmp = apply(:_HtmlBlock) + break if _tmp + self.pos = _save + + _save1 = self.pos + while true # sequence + _save2 = self.pos + + _save3 = self.pos + while true # sequence + _save4 = self.pos + _tmp = match_string("#") + _tmp = _tmp ? nil : true + self.pos = _save4 + unless _tmp + self.pos = _save3 + break + end + _save5 = self.pos + _tmp = apply(:_SetextBottom1) + _tmp = _tmp ? nil : true + self.pos = _save5 + unless _tmp + self.pos = _save3 + break + end + _save6 = self.pos + _tmp = apply(:_SetextBottom2) + _tmp = _tmp ? nil : true + self.pos = _save6 + unless _tmp + self.pos = _save3 + break + end + _save7 = self.pos + _tmp = _BlankLine() + _tmp = _tmp ? nil : true + self.pos = _save7 + unless _tmp + self.pos = _save3 + break + end + _tmp = _RawLine() + unless _tmp + self.pos = _save3 + end + break + end # end sequence + + if _tmp + while true + + _save8 = self.pos + while true # sequence + _save9 = self.pos + _tmp = match_string("#") + _tmp = _tmp ? nil : true + self.pos = _save9 + unless _tmp + self.pos = _save8 + break + end + _save10 = self.pos + _tmp = apply(:_SetextBottom1) + _tmp = _tmp ? nil : true + self.pos = _save10 + unless _tmp + self.pos = _save8 + break + end + _save11 = self.pos + _tmp = apply(:_SetextBottom2) + _tmp = _tmp ? nil : true + self.pos = _save11 + unless _tmp + self.pos = _save8 + break + end + _save12 = self.pos + _tmp = _BlankLine() + _tmp = _tmp ? nil : true + self.pos = _save12 + unless _tmp + self.pos = _save8 + break + end + _tmp = _RawLine() + unless _tmp + self.pos = _save8 + end + break + end # end sequence + + break unless _tmp + end + _tmp = true + else + self.pos = _save2 + end + unless _tmp + self.pos = _save1 + break + end + while true + _tmp = _BlankLine() + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save1 + end + break + end # end sequence + + break if _tmp + self.pos = _save + _save14 = self.pos + _tmp = _BlankLine() + if _tmp + while true + _tmp = _BlankLine() + break unless _tmp + end + _tmp = true + else + self.pos = _save14 + end + break if _tmp + self.pos = _save + _tmp = _RawLine() + break if _tmp + self.pos = _save + break + end # end choice + + set_failed_rule :_SkipBlock unless _tmp + return _tmp + end + + # ExtendedSpecialChar = &{ notes? } "^" + def _ExtendedSpecialChar + + _save = self.pos + while true # sequence + _save1 = self.pos + _tmp = begin; notes? ; end + self.pos = _save1 + unless _tmp + self.pos = _save + break + end + _tmp = match_string("^") + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_ExtendedSpecialChar unless _tmp + return _tmp + end + + # NoteReference = &{ notes? } RawNoteReference:ref { note_for ref } + def _NoteReference + + _save = self.pos + while true # sequence + _save1 = self.pos + _tmp = begin; notes? ; end + self.pos = _save1 + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_RawNoteReference) + ref = @result + unless _tmp + self.pos = _save + break + end + @result = begin; note_for ref ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_NoteReference unless _tmp + return _tmp + end + + # RawNoteReference = "[^" < (!@Newline !"]" .)+ > "]" { text } + def _RawNoteReference + + _save = self.pos + while true # sequence + _tmp = match_string("[^") + unless _tmp + self.pos = _save + break + end + _text_start = self.pos + _save1 = self.pos + + _save2 = self.pos + while true # sequence + _save3 = self.pos + _tmp = _Newline() + _tmp = _tmp ? nil : true + self.pos = _save3 + unless _tmp + self.pos = _save2 + break + end + _save4 = self.pos + _tmp = match_string("]") + _tmp = _tmp ? nil : true + self.pos = _save4 + unless _tmp + self.pos = _save2 + break + end + _tmp = get_byte + unless _tmp + self.pos = _save2 + end + break + end # end sequence + + if _tmp + while true + + _save5 = self.pos + while true # sequence + _save6 = self.pos + _tmp = _Newline() + _tmp = _tmp ? nil : true + self.pos = _save6 + unless _tmp + self.pos = _save5 + break + end + _save7 = self.pos + _tmp = match_string("]") + _tmp = _tmp ? nil : true + self.pos = _save7 + unless _tmp + self.pos = _save5 + break + end + _tmp = get_byte + unless _tmp + self.pos = _save5 + end + break + end # end sequence + + break unless _tmp + end + _tmp = true + else + self.pos = _save1 + end + if _tmp + text = get_text(_text_start) + end + unless _tmp + self.pos = _save + break + end + _tmp = match_string("]") + unless _tmp + self.pos = _save + break + end + @result = begin; text ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_RawNoteReference unless _tmp + return _tmp + end + + # Note = &{ notes? } @NonindentSpace RawNoteReference:ref ":" @Sp @StartList:a RawNoteBlock:i { a.concat i } (&Indent RawNoteBlock:i { a.concat i })* { @footnotes[ref] = paragraph a nil } + def _Note + + _save = self.pos + while true # sequence + _save1 = self.pos + _tmp = begin; notes? ; end + self.pos = _save1 + unless _tmp + self.pos = _save + break + end + _tmp = _NonindentSpace() + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_RawNoteReference) + ref = @result + unless _tmp + self.pos = _save + break + end + _tmp = match_string(":") + unless _tmp + self.pos = _save + break + end + _tmp = _Sp() + unless _tmp + self.pos = _save + break + end + _tmp = _StartList() + a = @result + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_RawNoteBlock) + i = @result + unless _tmp + self.pos = _save + break + end + @result = begin; a.concat i ; end + _tmp = true + unless _tmp + self.pos = _save + break + end + while true + + _save3 = self.pos + while true # sequence + _save4 = self.pos + _tmp = apply(:_Indent) + self.pos = _save4 + unless _tmp + self.pos = _save3 + break + end + _tmp = apply(:_RawNoteBlock) + i = @result + unless _tmp + self.pos = _save3 + break + end + @result = begin; a.concat i ; end + _tmp = true + unless _tmp + self.pos = _save3 + end + break + end # end sequence + + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + @result = begin; @footnotes[ref] = paragraph a + + nil + ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_Note unless _tmp + return _tmp + end + + # InlineNote = &{ notes? } "^[" @StartList:a (!"]" Inline:l { a << l })+ "]" { ref = [:inline, @note_order.length] @footnotes[ref] = paragraph a note_for ref } + def _InlineNote + + _save = self.pos + while true # sequence + _save1 = self.pos + _tmp = begin; notes? ; end + self.pos = _save1 + unless _tmp + self.pos = _save + break + end + _tmp = match_string("^[") + unless _tmp + self.pos = _save + break + end + _tmp = _StartList() + a = @result + unless _tmp + self.pos = _save + break + end + _save2 = self.pos + + _save3 = self.pos + while true # sequence + _save4 = self.pos + _tmp = match_string("]") + _tmp = _tmp ? nil : true + self.pos = _save4 + unless _tmp + self.pos = _save3 + break + end + _tmp = apply(:_Inline) + l = @result + unless _tmp + self.pos = _save3 + break + end + @result = begin; a << l ; end + _tmp = true + unless _tmp + self.pos = _save3 + end + break + end # end sequence + + if _tmp + while true + + _save5 = self.pos + while true # sequence + _save6 = self.pos + _tmp = match_string("]") + _tmp = _tmp ? nil : true + self.pos = _save6 + unless _tmp + self.pos = _save5 + break + end + _tmp = apply(:_Inline) + l = @result + unless _tmp + self.pos = _save5 + break + end + @result = begin; a << l ; end + _tmp = true + unless _tmp + self.pos = _save5 + end + break + end # end sequence + + break unless _tmp + end + _tmp = true + else + self.pos = _save2 + end + unless _tmp + self.pos = _save + break + end + _tmp = match_string("]") + unless _tmp + self.pos = _save + break + end + @result = begin; + ref = [:inline, @note_order.length] + @footnotes[ref] = paragraph a + + note_for ref + ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_InlineNote unless _tmp + return _tmp + end + + # Notes = (Note | SkipBlock)* + def _Notes + while true + + _save1 = self.pos + while true # choice + _tmp = apply(:_Note) + break if _tmp + self.pos = _save1 + _tmp = apply(:_SkipBlock) + break if _tmp + self.pos = _save1 + break + end # end choice + + break unless _tmp + end + _tmp = true + set_failed_rule :_Notes unless _tmp + return _tmp + end + + # RawNoteBlock = @StartList:a (!@BlankLine OptionallyIndentedLine:l { a << l })+ < @BlankLine* > { a << text } { a } + def _RawNoteBlock + + _save = self.pos + while true # sequence + _tmp = _StartList() + a = @result + unless _tmp + self.pos = _save + break + end + _save1 = self.pos + + _save2 = self.pos + while true # sequence + _save3 = self.pos + _tmp = _BlankLine() + _tmp = _tmp ? nil : true + self.pos = _save3 + unless _tmp + self.pos = _save2 + break + end + _tmp = apply(:_OptionallyIndentedLine) + l = @result + unless _tmp + self.pos = _save2 + break + end + @result = begin; a << l ; end + _tmp = true + unless _tmp + self.pos = _save2 + end + break + end # end sequence + + if _tmp + while true + + _save4 = self.pos + while true # sequence + _save5 = self.pos + _tmp = _BlankLine() + _tmp = _tmp ? nil : true + self.pos = _save5 + unless _tmp + self.pos = _save4 + break + end + _tmp = apply(:_OptionallyIndentedLine) + l = @result + unless _tmp + self.pos = _save4 + break + end + @result = begin; a << l ; end + _tmp = true + unless _tmp + self.pos = _save4 + end + break + end # end sequence + + break unless _tmp + end + _tmp = true + else + self.pos = _save1 + end + unless _tmp + self.pos = _save + break + end + _text_start = self.pos + while true + _tmp = _BlankLine() + break unless _tmp + end + _tmp = true + if _tmp + text = get_text(_text_start) + end + unless _tmp + self.pos = _save + break + end + @result = begin; a << text ; end + _tmp = true + unless _tmp + self.pos = _save + break + end + @result = begin; a ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_RawNoteBlock unless _tmp + return _tmp + end + + # CodeFence = &{ github? } Ticks3 (@Sp StrChunk:format)? Spnl < ((!"`" Nonspacechar)+ | !Ticks3 /`+/ | Spacechar | @Newline)+ > Ticks3 @Sp @Newline* { verbatim = RDoc::Markup::Verbatim.new text verbatim.format = format.intern if format verbatim } + def _CodeFence + + _save = self.pos + while true # sequence + _save1 = self.pos + _tmp = begin; github? ; end + self.pos = _save1 + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Ticks3) + unless _tmp + self.pos = _save + break + end + _save2 = self.pos + + _save3 = self.pos + while true # sequence + _tmp = _Sp() + unless _tmp + self.pos = _save3 + break + end + _tmp = apply(:_StrChunk) + format = @result + unless _tmp + self.pos = _save3 + end + break + end # end sequence + + unless _tmp + _tmp = true + self.pos = _save2 + end + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Spnl) + unless _tmp + self.pos = _save + break + end + _text_start = self.pos + _save4 = self.pos + + _save5 = self.pos + while true # choice + _save6 = self.pos + + _save7 = self.pos + while true # sequence + _save8 = self.pos + _tmp = match_string("`") + _tmp = _tmp ? nil : true + self.pos = _save8 + unless _tmp + self.pos = _save7 + break + end + _tmp = apply(:_Nonspacechar) + unless _tmp + self.pos = _save7 + end + break + end # end sequence + + if _tmp + while true + + _save9 = self.pos + while true # sequence + _save10 = self.pos + _tmp = match_string("`") + _tmp = _tmp ? nil : true + self.pos = _save10 + unless _tmp + self.pos = _save9 + break + end + _tmp = apply(:_Nonspacechar) + unless _tmp + self.pos = _save9 + end + break + end # end sequence + + break unless _tmp + end + _tmp = true + else + self.pos = _save6 + end + break if _tmp + self.pos = _save5 + + _save11 = self.pos + while true # sequence + _save12 = self.pos + _tmp = apply(:_Ticks3) + _tmp = _tmp ? nil : true + self.pos = _save12 + unless _tmp + self.pos = _save11 + break + end + _tmp = scan(/\A(?-mix:`+)/) + unless _tmp + self.pos = _save11 + end + break + end # end sequence + + break if _tmp + self.pos = _save5 + _tmp = apply(:_Spacechar) + break if _tmp + self.pos = _save5 + _tmp = _Newline() + break if _tmp + self.pos = _save5 + break + end # end choice + + if _tmp + while true + + _save13 = self.pos + while true # choice + _save14 = self.pos + + _save15 = self.pos + while true # sequence + _save16 = self.pos + _tmp = match_string("`") + _tmp = _tmp ? nil : true + self.pos = _save16 + unless _tmp + self.pos = _save15 + break + end + _tmp = apply(:_Nonspacechar) + unless _tmp + self.pos = _save15 + end + break + end # end sequence + + if _tmp + while true + + _save17 = self.pos + while true # sequence + _save18 = self.pos + _tmp = match_string("`") + _tmp = _tmp ? nil : true + self.pos = _save18 + unless _tmp + self.pos = _save17 + break + end + _tmp = apply(:_Nonspacechar) + unless _tmp + self.pos = _save17 + end + break + end # end sequence + + break unless _tmp + end + _tmp = true + else + self.pos = _save14 + end + break if _tmp + self.pos = _save13 + + _save19 = self.pos + while true # sequence + _save20 = self.pos + _tmp = apply(:_Ticks3) + _tmp = _tmp ? nil : true + self.pos = _save20 + unless _tmp + self.pos = _save19 + break + end + _tmp = scan(/\A(?-mix:`+)/) + unless _tmp + self.pos = _save19 + end + break + end # end sequence + + break if _tmp + self.pos = _save13 + _tmp = apply(:_Spacechar) + break if _tmp + self.pos = _save13 + _tmp = _Newline() + break if _tmp + self.pos = _save13 + break + end # end choice + + break unless _tmp + end + _tmp = true + else + self.pos = _save4 + end + if _tmp + text = get_text(_text_start) + end + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Ticks3) + unless _tmp + self.pos = _save + break + end + _tmp = _Sp() + unless _tmp + self.pos = _save + break + end + while true + _tmp = _Newline() + break unless _tmp + end + _tmp = true + unless _tmp + self.pos = _save + break + end + @result = begin; verbatim = RDoc::Markup::Verbatim.new text + verbatim.format = format.intern if format + verbatim + ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_CodeFence unless _tmp + return _tmp + end + + # DefinitionList = &{ definition_lists? } DefinitionListItem+:list { RDoc::Markup::List.new :NOTE, *list.flatten } + def _DefinitionList + + _save = self.pos + while true # sequence + _save1 = self.pos + _tmp = begin; definition_lists? ; end + self.pos = _save1 + unless _tmp + self.pos = _save + break + end + _save2 = self.pos + _ary = [] + _tmp = apply(:_DefinitionListItem) + if _tmp + _ary << @result + while true + _tmp = apply(:_DefinitionListItem) + _ary << @result if _tmp + break unless _tmp + end + _tmp = true + @result = _ary + else + self.pos = _save2 + end + list = @result + unless _tmp + self.pos = _save + break + end + @result = begin; RDoc::Markup::List.new :NOTE, *list.flatten ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_DefinitionList unless _tmp + return _tmp + end + + # DefinitionListItem = DefinitionListLabel+:label DefinitionListDefinition+:defns { list_items = [] list_items << RDoc::Markup::ListItem.new(label, defns.shift) list_items.concat defns.map { |defn| RDoc::Markup::ListItem.new nil, defn } unless list_items.empty? list_items } + def _DefinitionListItem + + _save = self.pos + while true # sequence + _save1 = self.pos + _ary = [] + _tmp = apply(:_DefinitionListLabel) + if _tmp + _ary << @result + while true + _tmp = apply(:_DefinitionListLabel) + _ary << @result if _tmp + break unless _tmp + end + _tmp = true + @result = _ary + else + self.pos = _save1 + end + label = @result + unless _tmp + self.pos = _save + break + end + _save2 = self.pos + _ary = [] + _tmp = apply(:_DefinitionListDefinition) + if _tmp + _ary << @result + while true + _tmp = apply(:_DefinitionListDefinition) + _ary << @result if _tmp + break unless _tmp + end + _tmp = true + @result = _ary + else + self.pos = _save2 + end + defns = @result + unless _tmp + self.pos = _save + break + end + @result = begin; list_items = [] + list_items << + RDoc::Markup::ListItem.new(label, defns.shift) + + list_items.concat defns.map { |defn| + RDoc::Markup::ListItem.new nil, defn + } unless list_items.empty? + + list_items + ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_DefinitionListItem unless _tmp + return _tmp + end + + # DefinitionListLabel = StrChunk:label @Sp @Newline { label } + def _DefinitionListLabel + + _save = self.pos + while true # sequence + _tmp = apply(:_StrChunk) + label = @result + unless _tmp + self.pos = _save + break + end + _tmp = _Sp() + unless _tmp + self.pos = _save + break + end + _tmp = _Newline() + unless _tmp + self.pos = _save + break + end + @result = begin; label ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_DefinitionListLabel unless _tmp + return _tmp + end + + # DefinitionListDefinition = @NonindentSpace ":" @Space Inlines:a @BlankLine+ { paragraph a } + def _DefinitionListDefinition + + _save = self.pos + while true # sequence + _tmp = _NonindentSpace() + unless _tmp + self.pos = _save + break + end + _tmp = match_string(":") + unless _tmp + self.pos = _save + break + end + _tmp = _Space() + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_Inlines) + a = @result + unless _tmp + self.pos = _save + break + end + _save1 = self.pos + _tmp = _BlankLine() + if _tmp + while true + _tmp = _BlankLine() + break unless _tmp + end + _tmp = true + else + self.pos = _save1 + end + unless _tmp + self.pos = _save + break + end + @result = begin; paragraph a ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_DefinitionListDefinition unless _tmp + return _tmp + end + + Rules = {} + Rules[:_root] = rule_info("root", "Doc") + Rules[:_Doc] = rule_info("Doc", "BOM? Block*:a { RDoc::Markup::Document.new(*a.compact) }") + Rules[:_Block] = rule_info("Block", "@BlankLine* (BlockQuote | Verbatim | CodeFence | Note | Reference | HorizontalRule | Heading | OrderedList | BulletList | DefinitionList | HtmlBlock | StyleBlock | Para | Plain)") + Rules[:_Para] = rule_info("Para", "@NonindentSpace Inlines:a @BlankLine+ { paragraph a }") + Rules[:_Plain] = rule_info("Plain", "Inlines:a { paragraph a }") + Rules[:_AtxInline] = rule_info("AtxInline", "!@Newline !(@Sp? /\#*/ @Sp @Newline) Inline") + Rules[:_AtxStart] = rule_info("AtxStart", "< /\\\#{1,6}/ > { text.length }") + Rules[:_AtxHeading] = rule_info("AtxHeading", "AtxStart:s @Sp? AtxInline+:a (@Sp? /\#*/ @Sp)? @Newline { RDoc::Markup::Heading.new(s, a.join) }") + Rules[:_SetextHeading] = rule_info("SetextHeading", "(SetextHeading1 | SetextHeading2)") + Rules[:_SetextBottom1] = rule_info("SetextBottom1", "/={3,}/ @Newline") + Rules[:_SetextBottom2] = rule_info("SetextBottom2", "/-{3,}/ @Newline") + Rules[:_SetextHeading1] = rule_info("SetextHeading1", "&(@RawLine SetextBottom1) @StartList:a (!@Endline Inline:b { a << b })+ @Sp? @Newline SetextBottom1 { RDoc::Markup::Heading.new(1, a.join) }") + Rules[:_SetextHeading2] = rule_info("SetextHeading2", "&(@RawLine SetextBottom2) @StartList:a (!@Endline Inline:b { a << b })+ @Sp? @Newline SetextBottom2 { RDoc::Markup::Heading.new(2, a.join) }") + Rules[:_Heading] = rule_info("Heading", "(SetextHeading | AtxHeading)") + Rules[:_BlockQuote] = rule_info("BlockQuote", "BlockQuoteRaw:a { RDoc::Markup::BlockQuote.new(*a) }") + Rules[:_BlockQuoteRaw] = rule_info("BlockQuoteRaw", "@StartList:a (\">\" \" \"? Line:l { a << l } (!\">\" !@BlankLine Line:c { a << c })* (@BlankLine:n { a << n })*)+ { inner_parse a.join }") + Rules[:_NonblankIndentedLine] = rule_info("NonblankIndentedLine", "!@BlankLine IndentedLine") + Rules[:_VerbatimChunk] = rule_info("VerbatimChunk", "@BlankLine*:a NonblankIndentedLine+:b { a.concat b }") + Rules[:_Verbatim] = rule_info("Verbatim", "VerbatimChunk+:a { RDoc::Markup::Verbatim.new(*a.flatten) }") + Rules[:_HorizontalRule] = rule_info("HorizontalRule", "@NonindentSpace (\"*\" @Sp \"*\" @Sp \"*\" (@Sp \"*\")* | \"-\" @Sp \"-\" @Sp \"-\" (@Sp \"-\")* | \"_\" @Sp \"_\" @Sp \"_\" (@Sp \"_\")*) @Sp @Newline @BlankLine+ { RDoc::Markup::Rule.new 1 }") + Rules[:_Bullet] = rule_info("Bullet", "!HorizontalRule @NonindentSpace /[+*-]/ @Spacechar+") + Rules[:_BulletList] = rule_info("BulletList", "&Bullet (ListTight | ListLoose):a { RDoc::Markup::List.new(:BULLET, *a) }") + Rules[:_ListTight] = rule_info("ListTight", "ListItemTight+:a @BlankLine* !(Bullet | Enumerator) { a }") + Rules[:_ListLoose] = rule_info("ListLoose", "@StartList:a (ListItem:b @BlankLine* { a << b })+ { a }") + Rules[:_ListItem] = rule_info("ListItem", "(Bullet | Enumerator) @StartList:a ListBlock:b { a << b } (ListContinuationBlock:c { a.push(*c) })* { list_item_from a }") + Rules[:_ListItemTight] = rule_info("ListItemTight", "(Bullet | Enumerator) ListBlock:a (!@BlankLine ListContinuationBlock:b { a.push(*b) })* !ListContinuationBlock { list_item_from a }") + Rules[:_ListBlock] = rule_info("ListBlock", "!@BlankLine Line:a ListBlockLine*:c { [a, *c] }") + Rules[:_ListContinuationBlock] = rule_info("ListContinuationBlock", "@StartList:a @BlankLine* { a << \"\\n\" } (Indent ListBlock:b { a.concat b })+ { a }") + Rules[:_Enumerator] = rule_info("Enumerator", "@NonindentSpace [0-9]+ \".\" @Spacechar+") + Rules[:_OrderedList] = rule_info("OrderedList", "&Enumerator (ListTight | ListLoose):a { RDoc::Markup::List.new(:NUMBER, *a) }") + Rules[:_ListBlockLine] = rule_info("ListBlockLine", "!@BlankLine !(Indent? (Bullet | Enumerator)) !HorizontalRule OptionallyIndentedLine") + Rules[:_HtmlOpenAnchor] = rule_info("HtmlOpenAnchor", "\"<\" Spnl (\"a\" | \"A\") Spnl HtmlAttribute* \">\"") + Rules[:_HtmlCloseAnchor] = rule_info("HtmlCloseAnchor", "\"<\" Spnl \"/\" (\"a\" | \"A\") Spnl \">\"") + Rules[:_HtmlAnchor] = rule_info("HtmlAnchor", "HtmlOpenAnchor (HtmlAnchor | !HtmlCloseAnchor .)* HtmlCloseAnchor") + Rules[:_HtmlBlockOpenAddress] = rule_info("HtmlBlockOpenAddress", "\"<\" Spnl (\"address\" | \"ADDRESS\") Spnl HtmlAttribute* \">\"") + Rules[:_HtmlBlockCloseAddress] = rule_info("HtmlBlockCloseAddress", "\"<\" Spnl \"/\" (\"address\" | \"ADDRESS\") Spnl \">\"") + Rules[:_HtmlBlockAddress] = rule_info("HtmlBlockAddress", "HtmlBlockOpenAddress (HtmlBlockAddress | !HtmlBlockCloseAddress .)* HtmlBlockCloseAddress") + Rules[:_HtmlBlockOpenBlockquote] = rule_info("HtmlBlockOpenBlockquote", "\"<\" Spnl (\"blockquote\" | \"BLOCKQUOTE\") Spnl HtmlAttribute* \">\"") + Rules[:_HtmlBlockCloseBlockquote] = rule_info("HtmlBlockCloseBlockquote", "\"<\" Spnl \"/\" (\"blockquote\" | \"BLOCKQUOTE\") Spnl \">\"") + Rules[:_HtmlBlockBlockquote] = rule_info("HtmlBlockBlockquote", "HtmlBlockOpenBlockquote (HtmlBlockBlockquote | !HtmlBlockCloseBlockquote .)* HtmlBlockCloseBlockquote") + Rules[:_HtmlBlockOpenCenter] = rule_info("HtmlBlockOpenCenter", "\"<\" Spnl (\"center\" | \"CENTER\") Spnl HtmlAttribute* \">\"") + Rules[:_HtmlBlockCloseCenter] = rule_info("HtmlBlockCloseCenter", "\"<\" Spnl \"/\" (\"center\" | \"CENTER\") Spnl \">\"") + Rules[:_HtmlBlockCenter] = rule_info("HtmlBlockCenter", "HtmlBlockOpenCenter (HtmlBlockCenter | !HtmlBlockCloseCenter .)* HtmlBlockCloseCenter") + Rules[:_HtmlBlockOpenDir] = rule_info("HtmlBlockOpenDir", "\"<\" Spnl (\"dir\" | \"DIR\") Spnl HtmlAttribute* \">\"") + Rules[:_HtmlBlockCloseDir] = rule_info("HtmlBlockCloseDir", "\"<\" Spnl \"/\" (\"dir\" | \"DIR\") Spnl \">\"") + Rules[:_HtmlBlockDir] = rule_info("HtmlBlockDir", "HtmlBlockOpenDir (HtmlBlockDir | !HtmlBlockCloseDir .)* HtmlBlockCloseDir") + Rules[:_HtmlBlockOpenDiv] = rule_info("HtmlBlockOpenDiv", "\"<\" Spnl (\"div\" | \"DIV\") Spnl HtmlAttribute* \">\"") + Rules[:_HtmlBlockCloseDiv] = rule_info("HtmlBlockCloseDiv", "\"<\" Spnl \"/\" (\"div\" | \"DIV\") Spnl \">\"") + Rules[:_HtmlBlockDiv] = rule_info("HtmlBlockDiv", "HtmlBlockOpenDiv (HtmlBlockDiv | !HtmlBlockCloseDiv .)* HtmlBlockCloseDiv") + Rules[:_HtmlBlockOpenDl] = rule_info("HtmlBlockOpenDl", "\"<\" Spnl (\"dl\" | \"DL\") Spnl HtmlAttribute* \">\"") + Rules[:_HtmlBlockCloseDl] = rule_info("HtmlBlockCloseDl", "\"<\" Spnl \"/\" (\"dl\" | \"DL\") Spnl \">\"") + Rules[:_HtmlBlockDl] = rule_info("HtmlBlockDl", "HtmlBlockOpenDl (HtmlBlockDl | !HtmlBlockCloseDl .)* HtmlBlockCloseDl") + Rules[:_HtmlBlockOpenFieldset] = rule_info("HtmlBlockOpenFieldset", "\"<\" Spnl (\"fieldset\" | \"FIELDSET\") Spnl HtmlAttribute* \">\"") + Rules[:_HtmlBlockCloseFieldset] = rule_info("HtmlBlockCloseFieldset", "\"<\" Spnl \"/\" (\"fieldset\" | \"FIELDSET\") Spnl \">\"") + Rules[:_HtmlBlockFieldset] = rule_info("HtmlBlockFieldset", "HtmlBlockOpenFieldset (HtmlBlockFieldset | !HtmlBlockCloseFieldset .)* HtmlBlockCloseFieldset") + Rules[:_HtmlBlockOpenForm] = rule_info("HtmlBlockOpenForm", "\"<\" Spnl (\"form\" | \"FORM\") Spnl HtmlAttribute* \">\"") + Rules[:_HtmlBlockCloseForm] = rule_info("HtmlBlockCloseForm", "\"<\" Spnl \"/\" (\"form\" | \"FORM\") Spnl \">\"") + Rules[:_HtmlBlockForm] = rule_info("HtmlBlockForm", "HtmlBlockOpenForm (HtmlBlockForm | !HtmlBlockCloseForm .)* HtmlBlockCloseForm") + Rules[:_HtmlBlockOpenH1] = rule_info("HtmlBlockOpenH1", "\"<\" Spnl (\"h1\" | \"H1\") Spnl HtmlAttribute* \">\"") + Rules[:_HtmlBlockCloseH1] = rule_info("HtmlBlockCloseH1", "\"<\" Spnl \"/\" (\"h1\" | \"H1\") Spnl \">\"") + Rules[:_HtmlBlockH1] = rule_info("HtmlBlockH1", "HtmlBlockOpenH1 (HtmlBlockH1 | !HtmlBlockCloseH1 .)* HtmlBlockCloseH1") + Rules[:_HtmlBlockOpenH2] = rule_info("HtmlBlockOpenH2", "\"<\" Spnl (\"h2\" | \"H2\") Spnl HtmlAttribute* \">\"") + Rules[:_HtmlBlockCloseH2] = rule_info("HtmlBlockCloseH2", "\"<\" Spnl \"/\" (\"h2\" | \"H2\") Spnl \">\"") + Rules[:_HtmlBlockH2] = rule_info("HtmlBlockH2", "HtmlBlockOpenH2 (HtmlBlockH2 | !HtmlBlockCloseH2 .)* HtmlBlockCloseH2") + Rules[:_HtmlBlockOpenH3] = rule_info("HtmlBlockOpenH3", "\"<\" Spnl (\"h3\" | \"H3\") Spnl HtmlAttribute* \">\"") + Rules[:_HtmlBlockCloseH3] = rule_info("HtmlBlockCloseH3", "\"<\" Spnl \"/\" (\"h3\" | \"H3\") Spnl \">\"") + Rules[:_HtmlBlockH3] = rule_info("HtmlBlockH3", "HtmlBlockOpenH3 (HtmlBlockH3 | !HtmlBlockCloseH3 .)* HtmlBlockCloseH3") + Rules[:_HtmlBlockOpenH4] = rule_info("HtmlBlockOpenH4", "\"<\" Spnl (\"h4\" | \"H4\") Spnl HtmlAttribute* \">\"") + Rules[:_HtmlBlockCloseH4] = rule_info("HtmlBlockCloseH4", "\"<\" Spnl \"/\" (\"h4\" | \"H4\") Spnl \">\"") + Rules[:_HtmlBlockH4] = rule_info("HtmlBlockH4", "HtmlBlockOpenH4 (HtmlBlockH4 | !HtmlBlockCloseH4 .)* HtmlBlockCloseH4") + Rules[:_HtmlBlockOpenH5] = rule_info("HtmlBlockOpenH5", "\"<\" Spnl (\"h5\" | \"H5\") Spnl HtmlAttribute* \">\"") + Rules[:_HtmlBlockCloseH5] = rule_info("HtmlBlockCloseH5", "\"<\" Spnl \"/\" (\"h5\" | \"H5\") Spnl \">\"") + Rules[:_HtmlBlockH5] = rule_info("HtmlBlockH5", "HtmlBlockOpenH5 (HtmlBlockH5 | !HtmlBlockCloseH5 .)* HtmlBlockCloseH5") + Rules[:_HtmlBlockOpenH6] = rule_info("HtmlBlockOpenH6", "\"<\" Spnl (\"h6\" | \"H6\") Spnl HtmlAttribute* \">\"") + Rules[:_HtmlBlockCloseH6] = rule_info("HtmlBlockCloseH6", "\"<\" Spnl \"/\" (\"h6\" | \"H6\") Spnl \">\"") + Rules[:_HtmlBlockH6] = rule_info("HtmlBlockH6", "HtmlBlockOpenH6 (HtmlBlockH6 | !HtmlBlockCloseH6 .)* HtmlBlockCloseH6") + Rules[:_HtmlBlockOpenMenu] = rule_info("HtmlBlockOpenMenu", "\"<\" Spnl (\"menu\" | \"MENU\") Spnl HtmlAttribute* \">\"") + Rules[:_HtmlBlockCloseMenu] = rule_info("HtmlBlockCloseMenu", "\"<\" Spnl \"/\" (\"menu\" | \"MENU\") Spnl \">\"") + Rules[:_HtmlBlockMenu] = rule_info("HtmlBlockMenu", "HtmlBlockOpenMenu (HtmlBlockMenu | !HtmlBlockCloseMenu .)* HtmlBlockCloseMenu") + Rules[:_HtmlBlockOpenNoframes] = rule_info("HtmlBlockOpenNoframes", "\"<\" Spnl (\"noframes\" | \"NOFRAMES\") Spnl HtmlAttribute* \">\"") + Rules[:_HtmlBlockCloseNoframes] = rule_info("HtmlBlockCloseNoframes", "\"<\" Spnl \"/\" (\"noframes\" | \"NOFRAMES\") Spnl \">\"") + Rules[:_HtmlBlockNoframes] = rule_info("HtmlBlockNoframes", "HtmlBlockOpenNoframes (HtmlBlockNoframes | !HtmlBlockCloseNoframes .)* HtmlBlockCloseNoframes") + Rules[:_HtmlBlockOpenNoscript] = rule_info("HtmlBlockOpenNoscript", "\"<\" Spnl (\"noscript\" | \"NOSCRIPT\") Spnl HtmlAttribute* \">\"") + Rules[:_HtmlBlockCloseNoscript] = rule_info("HtmlBlockCloseNoscript", "\"<\" Spnl \"/\" (\"noscript\" | \"NOSCRIPT\") Spnl \">\"") + Rules[:_HtmlBlockNoscript] = rule_info("HtmlBlockNoscript", "HtmlBlockOpenNoscript (HtmlBlockNoscript | !HtmlBlockCloseNoscript .)* HtmlBlockCloseNoscript") + Rules[:_HtmlBlockOpenOl] = rule_info("HtmlBlockOpenOl", "\"<\" Spnl (\"ol\" | \"OL\") Spnl HtmlAttribute* \">\"") + Rules[:_HtmlBlockCloseOl] = rule_info("HtmlBlockCloseOl", "\"<\" Spnl \"/\" (\"ol\" | \"OL\") Spnl \">\"") + Rules[:_HtmlBlockOl] = rule_info("HtmlBlockOl", "HtmlBlockOpenOl (HtmlBlockOl | !HtmlBlockCloseOl .)* HtmlBlockCloseOl") + Rules[:_HtmlBlockOpenP] = rule_info("HtmlBlockOpenP", "\"<\" Spnl (\"p\" | \"P\") Spnl HtmlAttribute* \">\"") + Rules[:_HtmlBlockCloseP] = rule_info("HtmlBlockCloseP", "\"<\" Spnl \"/\" (\"p\" | \"P\") Spnl \">\"") + Rules[:_HtmlBlockP] = rule_info("HtmlBlockP", "HtmlBlockOpenP (HtmlBlockP | !HtmlBlockCloseP .)* HtmlBlockCloseP") + Rules[:_HtmlBlockOpenPre] = rule_info("HtmlBlockOpenPre", "\"<\" Spnl (\"pre\" | \"PRE\") Spnl HtmlAttribute* \">\"") + Rules[:_HtmlBlockClosePre] = rule_info("HtmlBlockClosePre", "\"<\" Spnl \"/\" (\"pre\" | \"PRE\") Spnl \">\"") + Rules[:_HtmlBlockPre] = rule_info("HtmlBlockPre", "HtmlBlockOpenPre (HtmlBlockPre | !HtmlBlockClosePre .)* HtmlBlockClosePre") + Rules[:_HtmlBlockOpenTable] = rule_info("HtmlBlockOpenTable", "\"<\" Spnl (\"table\" | \"TABLE\") Spnl HtmlAttribute* \">\"") + Rules[:_HtmlBlockCloseTable] = rule_info("HtmlBlockCloseTable", "\"<\" Spnl \"/\" (\"table\" | \"TABLE\") Spnl \">\"") + Rules[:_HtmlBlockTable] = rule_info("HtmlBlockTable", "HtmlBlockOpenTable (HtmlBlockTable | !HtmlBlockCloseTable .)* HtmlBlockCloseTable") + Rules[:_HtmlBlockOpenUl] = rule_info("HtmlBlockOpenUl", "\"<\" Spnl (\"ul\" | \"UL\") Spnl HtmlAttribute* \">\"") + Rules[:_HtmlBlockCloseUl] = rule_info("HtmlBlockCloseUl", "\"<\" Spnl \"/\" (\"ul\" | \"UL\") Spnl \">\"") + Rules[:_HtmlBlockUl] = rule_info("HtmlBlockUl", "HtmlBlockOpenUl (HtmlBlockUl | !HtmlBlockCloseUl .)* HtmlBlockCloseUl") + Rules[:_HtmlBlockOpenDd] = rule_info("HtmlBlockOpenDd", "\"<\" Spnl (\"dd\" | \"DD\") Spnl HtmlAttribute* \">\"") + Rules[:_HtmlBlockCloseDd] = rule_info("HtmlBlockCloseDd", "\"<\" Spnl \"/\" (\"dd\" | \"DD\") Spnl \">\"") + Rules[:_HtmlBlockDd] = rule_info("HtmlBlockDd", "HtmlBlockOpenDd (HtmlBlockDd | !HtmlBlockCloseDd .)* HtmlBlockCloseDd") + Rules[:_HtmlBlockOpenDt] = rule_info("HtmlBlockOpenDt", "\"<\" Spnl (\"dt\" | \"DT\") Spnl HtmlAttribute* \">\"") + Rules[:_HtmlBlockCloseDt] = rule_info("HtmlBlockCloseDt", "\"<\" Spnl \"/\" (\"dt\" | \"DT\") Spnl \">\"") + Rules[:_HtmlBlockDt] = rule_info("HtmlBlockDt", "HtmlBlockOpenDt (HtmlBlockDt | !HtmlBlockCloseDt .)* HtmlBlockCloseDt") + Rules[:_HtmlBlockOpenFrameset] = rule_info("HtmlBlockOpenFrameset", "\"<\" Spnl (\"frameset\" | \"FRAMESET\") Spnl HtmlAttribute* \">\"") + Rules[:_HtmlBlockCloseFrameset] = rule_info("HtmlBlockCloseFrameset", "\"<\" Spnl \"/\" (\"frameset\" | \"FRAMESET\") Spnl \">\"") + Rules[:_HtmlBlockFrameset] = rule_info("HtmlBlockFrameset", "HtmlBlockOpenFrameset (HtmlBlockFrameset | !HtmlBlockCloseFrameset .)* HtmlBlockCloseFrameset") + Rules[:_HtmlBlockOpenLi] = rule_info("HtmlBlockOpenLi", "\"<\" Spnl (\"li\" | \"LI\") Spnl HtmlAttribute* \">\"") + Rules[:_HtmlBlockCloseLi] = rule_info("HtmlBlockCloseLi", "\"<\" Spnl \"/\" (\"li\" | \"LI\") Spnl \">\"") + Rules[:_HtmlBlockLi] = rule_info("HtmlBlockLi", "HtmlBlockOpenLi (HtmlBlockLi | !HtmlBlockCloseLi .)* HtmlBlockCloseLi") + Rules[:_HtmlBlockOpenTbody] = rule_info("HtmlBlockOpenTbody", "\"<\" Spnl (\"tbody\" | \"TBODY\") Spnl HtmlAttribute* \">\"") + Rules[:_HtmlBlockCloseTbody] = rule_info("HtmlBlockCloseTbody", "\"<\" Spnl \"/\" (\"tbody\" | \"TBODY\") Spnl \">\"") + Rules[:_HtmlBlockTbody] = rule_info("HtmlBlockTbody", "HtmlBlockOpenTbody (HtmlBlockTbody | !HtmlBlockCloseTbody .)* HtmlBlockCloseTbody") + Rules[:_HtmlBlockOpenTd] = rule_info("HtmlBlockOpenTd", "\"<\" Spnl (\"td\" | \"TD\") Spnl HtmlAttribute* \">\"") + Rules[:_HtmlBlockCloseTd] = rule_info("HtmlBlockCloseTd", "\"<\" Spnl \"/\" (\"td\" | \"TD\") Spnl \">\"") + Rules[:_HtmlBlockTd] = rule_info("HtmlBlockTd", "HtmlBlockOpenTd (HtmlBlockTd | !HtmlBlockCloseTd .)* HtmlBlockCloseTd") + Rules[:_HtmlBlockOpenTfoot] = rule_info("HtmlBlockOpenTfoot", "\"<\" Spnl (\"tfoot\" | \"TFOOT\") Spnl HtmlAttribute* \">\"") + Rules[:_HtmlBlockCloseTfoot] = rule_info("HtmlBlockCloseTfoot", "\"<\" Spnl \"/\" (\"tfoot\" | \"TFOOT\") Spnl \">\"") + Rules[:_HtmlBlockTfoot] = rule_info("HtmlBlockTfoot", "HtmlBlockOpenTfoot (HtmlBlockTfoot | !HtmlBlockCloseTfoot .)* HtmlBlockCloseTfoot") + Rules[:_HtmlBlockOpenTh] = rule_info("HtmlBlockOpenTh", "\"<\" Spnl (\"th\" | \"TH\") Spnl HtmlAttribute* \">\"") + Rules[:_HtmlBlockCloseTh] = rule_info("HtmlBlockCloseTh", "\"<\" Spnl \"/\" (\"th\" | \"TH\") Spnl \">\"") + Rules[:_HtmlBlockTh] = rule_info("HtmlBlockTh", "HtmlBlockOpenTh (HtmlBlockTh | !HtmlBlockCloseTh .)* HtmlBlockCloseTh") + Rules[:_HtmlBlockOpenThead] = rule_info("HtmlBlockOpenThead", "\"<\" Spnl (\"thead\" | \"THEAD\") Spnl HtmlAttribute* \">\"") + Rules[:_HtmlBlockCloseThead] = rule_info("HtmlBlockCloseThead", "\"<\" Spnl \"/\" (\"thead\" | \"THEAD\") Spnl \">\"") + Rules[:_HtmlBlockThead] = rule_info("HtmlBlockThead", "HtmlBlockOpenThead (HtmlBlockThead | !HtmlBlockCloseThead .)* HtmlBlockCloseThead") + Rules[:_HtmlBlockOpenTr] = rule_info("HtmlBlockOpenTr", "\"<\" Spnl (\"tr\" | \"TR\") Spnl HtmlAttribute* \">\"") + Rules[:_HtmlBlockCloseTr] = rule_info("HtmlBlockCloseTr", "\"<\" Spnl \"/\" (\"tr\" | \"TR\") Spnl \">\"") + Rules[:_HtmlBlockTr] = rule_info("HtmlBlockTr", "HtmlBlockOpenTr (HtmlBlockTr | !HtmlBlockCloseTr .)* HtmlBlockCloseTr") + Rules[:_HtmlBlockOpenScript] = rule_info("HtmlBlockOpenScript", "\"<\" Spnl (\"script\" | \"SCRIPT\") Spnl HtmlAttribute* \">\"") + Rules[:_HtmlBlockCloseScript] = rule_info("HtmlBlockCloseScript", "\"<\" Spnl \"/\" (\"script\" | \"SCRIPT\") Spnl \">\"") + Rules[:_HtmlBlockScript] = rule_info("HtmlBlockScript", "HtmlBlockOpenScript (!HtmlBlockCloseScript .)* HtmlBlockCloseScript") + Rules[:_HtmlBlockInTags] = rule_info("HtmlBlockInTags", "(HtmlAnchor | HtmlBlockAddress | HtmlBlockBlockquote | HtmlBlockCenter | HtmlBlockDir | HtmlBlockDiv | HtmlBlockDl | HtmlBlockFieldset | HtmlBlockForm | HtmlBlockH1 | HtmlBlockH2 | HtmlBlockH3 | HtmlBlockH4 | HtmlBlockH5 | HtmlBlockH6 | HtmlBlockMenu | HtmlBlockNoframes | HtmlBlockNoscript | HtmlBlockOl | HtmlBlockP | HtmlBlockPre | HtmlBlockTable | HtmlBlockUl | HtmlBlockDd | HtmlBlockDt | HtmlBlockFrameset | HtmlBlockLi | HtmlBlockTbody | HtmlBlockTd | HtmlBlockTfoot | HtmlBlockTh | HtmlBlockThead | HtmlBlockTr | HtmlBlockScript)") + Rules[:_HtmlBlock] = rule_info("HtmlBlock", "< (HtmlBlockInTags | HtmlComment | HtmlBlockSelfClosing | HtmlUnclosed) > @BlankLine+ { if html? then RDoc::Markup::Raw.new text end }") + Rules[:_HtmlUnclosed] = rule_info("HtmlUnclosed", "\"<\" Spnl HtmlUnclosedType Spnl HtmlAttribute* Spnl \">\"") + Rules[:_HtmlUnclosedType] = rule_info("HtmlUnclosedType", "(\"HR\" | \"hr\")") + Rules[:_HtmlBlockSelfClosing] = rule_info("HtmlBlockSelfClosing", "\"<\" Spnl HtmlBlockType Spnl HtmlAttribute* \"/\" Spnl \">\"") + Rules[:_HtmlBlockType] = rule_info("HtmlBlockType", "(\"ADDRESS\" | \"BLOCKQUOTE\" | \"CENTER\" | \"DD\" | \"DIR\" | \"DIV\" | \"DL\" | \"DT\" | \"FIELDSET\" | \"FORM\" | \"FRAMESET\" | \"H1\" | \"H2\" | \"H3\" | \"H4\" | \"H5\" | \"H6\" | \"HR\" | \"ISINDEX\" | \"LI\" | \"MENU\" | \"NOFRAMES\" | \"NOSCRIPT\" | \"OL\" | \"P\" | \"PRE\" | \"SCRIPT\" | \"TABLE\" | \"TBODY\" | \"TD\" | \"TFOOT\" | \"TH\" | \"THEAD\" | \"TR\" | \"UL\" | \"address\" | \"blockquote\" | \"center\" | \"dd\" | \"dir\" | \"div\" | \"dl\" | \"dt\" | \"fieldset\" | \"form\" | \"frameset\" | \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"hr\" | \"isindex\" | \"li\" | \"menu\" | \"noframes\" | \"noscript\" | \"ol\" | \"p\" | \"pre\" | \"script\" | \"table\" | \"tbody\" | \"td\" | \"tfoot\" | \"th\" | \"thead\" | \"tr\" | \"ul\")") + Rules[:_StyleOpen] = rule_info("StyleOpen", "\"<\" Spnl (\"style\" | \"STYLE\") Spnl HtmlAttribute* \">\"") + Rules[:_StyleClose] = rule_info("StyleClose", "\"<\" Spnl \"/\" (\"style\" | \"STYLE\") Spnl \">\"") + Rules[:_InStyleTags] = rule_info("InStyleTags", "StyleOpen (!StyleClose .)* StyleClose") + Rules[:_StyleBlock] = rule_info("StyleBlock", "< InStyleTags > @BlankLine* { if css? then RDoc::Markup::Raw.new text end }") + Rules[:_Inlines] = rule_info("Inlines", "(!@Endline Inline:i { i } | @Endline:c &Inline { c })+:chunks @Endline? { chunks }") + Rules[:_Inline] = rule_info("Inline", "(Str | @Endline | UlOrStarLine | @Space | Strong | Emph | Image | Link | NoteReference | InlineNote | Code | RawHtml | Entity | EscapedChar | Symbol)") + Rules[:_Space] = rule_info("Space", "@Spacechar+ { \" \" }") + Rules[:_Str] = rule_info("Str", "@StartList:a < @NormalChar+ > { a = text } (StrChunk:c { a << c })* { a }") + Rules[:_StrChunk] = rule_info("StrChunk", "< (@NormalChar | /_+/ &Alphanumeric)+ > { text }") + Rules[:_EscapedChar] = rule_info("EscapedChar", "\"\\\\\" !@Newline < /[:\\\\`|*_{}\\[\\]()\#+.!><-]/ > { text }") + Rules[:_Entity] = rule_info("Entity", "(HexEntity | DecEntity | CharEntity):a { a }") + Rules[:_Endline] = rule_info("Endline", "(@LineBreak | @TerminalEndline | @NormalEndline)") + Rules[:_NormalEndline] = rule_info("NormalEndline", "@Sp @Newline !@BlankLine !\">\" !AtxStart !(Line /={3,}|-{3,}=/ @Newline) { \"\\n\" }") + Rules[:_TerminalEndline] = rule_info("TerminalEndline", "@Sp @Newline @Eof") + Rules[:_LineBreak] = rule_info("LineBreak", "\" \" @NormalEndline { RDoc::Markup::HardBreak.new }") + Rules[:_Symbol] = rule_info("Symbol", "< @SpecialChar > { text }") + Rules[:_UlOrStarLine] = rule_info("UlOrStarLine", "(UlLine | StarLine):a { a }") + Rules[:_StarLine] = rule_info("StarLine", "(< /\\*{4,}/ > { text } | < @Spacechar /\\*+/ &@Spacechar > { text })") + Rules[:_UlLine] = rule_info("UlLine", "(< /_{4,}/ > { text } | < @Spacechar /_+/ &@Spacechar > { text })") + Rules[:_Emph] = rule_info("Emph", "(EmphStar | EmphUl)") + Rules[:_OneStarOpen] = rule_info("OneStarOpen", "!StarLine \"*\" !@Spacechar !@Newline") + Rules[:_OneStarClose] = rule_info("OneStarClose", "!@Spacechar !@Newline Inline:a \"*\" { a }") + Rules[:_EmphStar] = rule_info("EmphStar", "OneStarOpen @StartList:a (!OneStarClose Inline:l { a << l })* OneStarClose:l { a << l } { emphasis a.join }") + Rules[:_OneUlOpen] = rule_info("OneUlOpen", "!UlLine \"_\" !@Spacechar !@Newline") + Rules[:_OneUlClose] = rule_info("OneUlClose", "!@Spacechar !@Newline Inline:a \"_\" { a }") + Rules[:_EmphUl] = rule_info("EmphUl", "OneUlOpen @StartList:a (!OneUlClose Inline:l { a << l })* OneUlClose:l { a << l } { emphasis a.join }") + Rules[:_Strong] = rule_info("Strong", "(StrongStar | StrongUl)") + Rules[:_TwoStarOpen] = rule_info("TwoStarOpen", "!StarLine \"**\" !@Spacechar !@Newline") + Rules[:_TwoStarClose] = rule_info("TwoStarClose", "!@Spacechar !@Newline Inline:a \"**\" { a }") + Rules[:_StrongStar] = rule_info("StrongStar", "TwoStarOpen @StartList:a (!TwoStarClose Inline:l { a << l })* TwoStarClose:l { a << l } { strong a.join }") + Rules[:_TwoUlOpen] = rule_info("TwoUlOpen", "!UlLine \"__\" !@Spacechar !@Newline") + Rules[:_TwoUlClose] = rule_info("TwoUlClose", "!@Spacechar !@Newline Inline:a \"__\" { a }") + Rules[:_StrongUl] = rule_info("StrongUl", "TwoUlOpen @StartList:a (!TwoUlClose Inline:i { a << i })* TwoUlClose:l { a << l } { strong a.join }") + Rules[:_Image] = rule_info("Image", "\"!\" (ExplicitLink | ReferenceLink):a { \"rdoc-image:\#{a[/\\[(.*)\\]/, 1]}\" }") + Rules[:_Link] = rule_info("Link", "(ExplicitLink | ReferenceLink | AutoLink)") + Rules[:_ReferenceLink] = rule_info("ReferenceLink", "(ReferenceLinkDouble | ReferenceLinkSingle)") + Rules[:_ReferenceLinkDouble] = rule_info("ReferenceLinkDouble", "Label:content < Spnl > !\"[]\" Label:label { link_to content, label, text }") + Rules[:_ReferenceLinkSingle] = rule_info("ReferenceLinkSingle", "Label:content < (Spnl \"[]\")? > { link_to content, content, text }") + Rules[:_ExplicitLink] = rule_info("ExplicitLink", "Label:l Spnl \"(\" @Sp Source:s Spnl Title @Sp \")\" { \"{\#{l}}[\#{s}]\" }") + Rules[:_Source] = rule_info("Source", "(\"<\" < SourceContents > \">\" | < SourceContents >) { text }") + Rules[:_SourceContents] = rule_info("SourceContents", "(((!\"(\" !\")\" !\">\" Nonspacechar)+ | \"(\" SourceContents \")\")* | \"\")") + Rules[:_Title] = rule_info("Title", "(TitleSingle | TitleDouble | \"\"):a { a }") + Rules[:_TitleSingle] = rule_info("TitleSingle", "\"'\" (!(\"'\" @Sp (\")\" | @Newline)) .)* \"'\"") + Rules[:_TitleDouble] = rule_info("TitleDouble", "\"\\\"\" (!(\"\\\"\" @Sp (\")\" | @Newline)) .)* \"\\\"\"") + Rules[:_AutoLink] = rule_info("AutoLink", "(AutoLinkUrl | AutoLinkEmail)") + Rules[:_AutoLinkUrl] = rule_info("AutoLinkUrl", "\"<\" < /[A-Za-z]+/ \"://\" (!@Newline !\">\" .)+ > \">\" { text }") + Rules[:_AutoLinkEmail] = rule_info("AutoLinkEmail", "\"<\" \"mailto:\"? < /[\\w+.\\/!%~$-]+/i \"@\" (!@Newline !\">\" .)+ > \">\" { \"mailto:\#{text}\" }") + Rules[:_Reference] = rule_info("Reference", "@NonindentSpace !\"[]\" Label:label \":\" Spnl RefSrc:link RefTitle @BlankLine+ { \# TODO use title reference label, link nil }") + Rules[:_Label] = rule_info("Label", "\"[\" (!\"^\" &{ notes? } | &. &{ !notes? }) @StartList:a (!\"]\" Inline:l { a << l })* \"]\" { a.join.gsub(/\\s+/, ' ') }") + Rules[:_RefSrc] = rule_info("RefSrc", "< Nonspacechar+ > { text }") + Rules[:_RefTitle] = rule_info("RefTitle", "(RefTitleSingle | RefTitleDouble | RefTitleParens | EmptyTitle)") + Rules[:_EmptyTitle] = rule_info("EmptyTitle", "\"\"") + Rules[:_RefTitleSingle] = rule_info("RefTitleSingle", "Spnl \"'\" < (!(\"'\" @Sp @Newline | @Newline) .)* > \"'\" { text }") + Rules[:_RefTitleDouble] = rule_info("RefTitleDouble", "Spnl \"\\\"\" < (!(\"\\\"\" @Sp @Newline | @Newline) .)* > \"\\\"\" { text }") + Rules[:_RefTitleParens] = rule_info("RefTitleParens", "Spnl \"(\" < (!(\")\" @Sp @Newline | @Newline) .)* > \")\" { text }") + Rules[:_References] = rule_info("References", "(Reference | SkipBlock)*") + Rules[:_Ticks1] = rule_info("Ticks1", "\"`\" !\"`\"") + Rules[:_Ticks2] = rule_info("Ticks2", "\"``\" !\"`\"") + Rules[:_Ticks3] = rule_info("Ticks3", "\"```\" !\"`\"") + Rules[:_Ticks4] = rule_info("Ticks4", "\"````\" !\"`\"") + Rules[:_Ticks5] = rule_info("Ticks5", "\"`````\" !\"`\"") + Rules[:_Code] = rule_info("Code", "(Ticks1 @Sp < ((!\"`\" Nonspacechar)+ | !Ticks1 /`+/ | !(@Sp Ticks1) (@Spacechar | @Newline !@BlankLine))+ > @Sp Ticks1 | Ticks2 @Sp < ((!\"`\" Nonspacechar)+ | !Ticks2 /`+/ | !(@Sp Ticks2) (@Spacechar | @Newline !@BlankLine))+ > @Sp Ticks2 | Ticks3 @Sp < ((!\"`\" Nonspacechar)+ | !Ticks3 /`+/ | !(@Sp Ticks3) (@Spacechar | @Newline !@BlankLine))+ > @Sp Ticks3 | Ticks4 @Sp < ((!\"`\" Nonspacechar)+ | !Ticks4 /`+/ | !(@Sp Ticks4) (@Spacechar | @Newline !@BlankLine))+ > @Sp Ticks4 | Ticks5 @Sp < ((!\"`\" Nonspacechar)+ | !Ticks5 /`+/ | !(@Sp Ticks5) (@Spacechar | @Newline !@BlankLine))+ > @Sp Ticks5) { \"<code>\#{text}</code>\" }") + Rules[:_RawHtml] = rule_info("RawHtml", "< (HtmlComment | HtmlBlockScript | HtmlTag) > { if html? then text else '' end }") + Rules[:_BlankLine] = rule_info("BlankLine", "@Sp @Newline { \"\\n\" }") + Rules[:_Quoted] = rule_info("Quoted", "(\"\\\"\" (!\"\\\"\" .)* \"\\\"\" | \"'\" (!\"'\" .)* \"'\")") + Rules[:_HtmlAttribute] = rule_info("HtmlAttribute", "(AlphanumericAscii | \"-\")+ Spnl (\"=\" Spnl (Quoted | (!\">\" Nonspacechar)+))? Spnl") + Rules[:_HtmlComment] = rule_info("HtmlComment", "\"<!--\" (!\"-->\" .)* \"-->\"") + Rules[:_HtmlTag] = rule_info("HtmlTag", "\"<\" Spnl \"/\"? AlphanumericAscii+ Spnl HtmlAttribute* \"/\"? Spnl \">\"") + Rules[:_Eof] = rule_info("Eof", "!.") + Rules[:_Nonspacechar] = rule_info("Nonspacechar", "!@Spacechar !@Newline .") + Rules[:_Sp] = rule_info("Sp", "@Spacechar*") + Rules[:_Spnl] = rule_info("Spnl", "@Sp (@Newline @Sp)?") + Rules[:_SpecialChar] = rule_info("SpecialChar", "(/[*_`&\\[\\]()<!\#\\\\'\"]/ | @ExtendedSpecialChar)") + Rules[:_NormalChar] = rule_info("NormalChar", "!(@SpecialChar | @Spacechar | @Newline) .") + Rules[:_Digit] = rule_info("Digit", "[0-9]") + Rules[:_Alphanumeric] = rule_info("Alphanumeric", "%literals.Alphanumeric") + Rules[:_AlphanumericAscii] = rule_info("AlphanumericAscii", "%literals.AlphanumericAscii") + Rules[:_BOM] = rule_info("BOM", "%literals.BOM") + Rules[:_Newline] = rule_info("Newline", "%literals.Newline") + Rules[:_NonAlphanumeric] = rule_info("NonAlphanumeric", "%literals.NonAlphanumeric") + Rules[:_Spacechar] = rule_info("Spacechar", "%literals.Spacechar") + Rules[:_HexEntity] = rule_info("HexEntity", "/&\#x/i < /[0-9a-fA-F]+/ > \";\" { [text.to_i(16)].pack 'U' }") + Rules[:_DecEntity] = rule_info("DecEntity", "\"&\#\" < /[0-9]+/ > \";\" { [text.to_i].pack 'U' }") + Rules[:_CharEntity] = rule_info("CharEntity", "\"&\" < /[A-Za-z0-9]+/ > \";\" { if entity = HTML_ENTITIES[text] then entity.pack 'U*' else \"&\#{text};\" end }") + Rules[:_NonindentSpace] = rule_info("NonindentSpace", "/ {0,3}/") + Rules[:_Indent] = rule_info("Indent", "/\\t| /") + Rules[:_IndentedLine] = rule_info("IndentedLine", "Indent Line") + Rules[:_OptionallyIndentedLine] = rule_info("OptionallyIndentedLine", "Indent? Line") + Rules[:_StartList] = rule_info("StartList", "&. { [] }") + Rules[:_Line] = rule_info("Line", "@RawLine:a { a }") + Rules[:_RawLine] = rule_info("RawLine", "(< (!\"\\r\" !\"\\n\" .)* @Newline > | < .+ > @Eof) { text }") + Rules[:_SkipBlock] = rule_info("SkipBlock", "(HtmlBlock | (!\"\#\" !SetextBottom1 !SetextBottom2 !@BlankLine @RawLine)+ @BlankLine* | @BlankLine+ | @RawLine)") + Rules[:_ExtendedSpecialChar] = rule_info("ExtendedSpecialChar", "&{ notes? } \"^\"") + Rules[:_NoteReference] = rule_info("NoteReference", "&{ notes? } RawNoteReference:ref { note_for ref }") + Rules[:_RawNoteReference] = rule_info("RawNoteReference", "\"[^\" < (!@Newline !\"]\" .)+ > \"]\" { text }") + Rules[:_Note] = rule_info("Note", "&{ notes? } @NonindentSpace RawNoteReference:ref \":\" @Sp @StartList:a RawNoteBlock:i { a.concat i } (&Indent RawNoteBlock:i { a.concat i })* { @footnotes[ref] = paragraph a nil }") + Rules[:_InlineNote] = rule_info("InlineNote", "&{ notes? } \"^[\" @StartList:a (!\"]\" Inline:l { a << l })+ \"]\" { ref = [:inline, @note_order.length] @footnotes[ref] = paragraph a note_for ref }") + Rules[:_Notes] = rule_info("Notes", "(Note | SkipBlock)*") + Rules[:_RawNoteBlock] = rule_info("RawNoteBlock", "@StartList:a (!@BlankLine OptionallyIndentedLine:l { a << l })+ < @BlankLine* > { a << text } { a }") + Rules[:_CodeFence] = rule_info("CodeFence", "&{ github? } Ticks3 (@Sp StrChunk:format)? Spnl < ((!\"`\" Nonspacechar)+ | !Ticks3 /`+/ | Spacechar | @Newline)+ > Ticks3 @Sp @Newline* { verbatim = RDoc::Markup::Verbatim.new text verbatim.format = format.intern if format verbatim }") + Rules[:_DefinitionList] = rule_info("DefinitionList", "&{ definition_lists? } DefinitionListItem+:list { RDoc::Markup::List.new :NOTE, *list.flatten }") + Rules[:_DefinitionListItem] = rule_info("DefinitionListItem", "DefinitionListLabel+:label DefinitionListDefinition+:defns { list_items = [] list_items << RDoc::Markup::ListItem.new(label, defns.shift) list_items.concat defns.map { |defn| RDoc::Markup::ListItem.new nil, defn } unless list_items.empty? list_items }") + Rules[:_DefinitionListLabel] = rule_info("DefinitionListLabel", "StrChunk:label @Sp @Newline { label }") + Rules[:_DefinitionListDefinition] = rule_info("DefinitionListDefinition", "@NonindentSpace \":\" @Space Inlines:a @BlankLine+ { paragraph a }") + # :startdoc: +end diff --git a/jni/ruby/lib/rdoc/markdown/entities.rb b/jni/ruby/lib/rdoc/markdown/entities.rb new file mode 100644 index 0000000..0661aba --- /dev/null +++ b/jni/ruby/lib/rdoc/markdown/entities.rb @@ -0,0 +1,2131 @@ +## +# HTML entity name map for RDoc::Markdown + +RDoc::Markdown::HTML_ENTITIES = { + "AElig" => [0x000C6], + "AMP" => [0x00026], + "Aacute" => [0x000C1], + "Abreve" => [0x00102], + "Acirc" => [0x000C2], + "Acy" => [0x00410], + "Afr" => [0x1D504], + "Agrave" => [0x000C0], + "Alpha" => [0x00391], + "Amacr" => [0x00100], + "And" => [0x02A53], + "Aogon" => [0x00104], + "Aopf" => [0x1D538], + "ApplyFunction" => [0x02061], + "Aring" => [0x000C5], + "Ascr" => [0x1D49C], + "Assign" => [0x02254], + "Atilde" => [0x000C3], + "Auml" => [0x000C4], + "Backslash" => [0x02216], + "Barv" => [0x02AE7], + "Barwed" => [0x02306], + "Bcy" => [0x00411], + "Because" => [0x02235], + "Bernoullis" => [0x0212C], + "Beta" => [0x00392], + "Bfr" => [0x1D505], + "Bopf" => [0x1D539], + "Breve" => [0x002D8], + "Bscr" => [0x0212C], + "Bumpeq" => [0x0224E], + "CHcy" => [0x00427], + "COPY" => [0x000A9], + "Cacute" => [0x00106], + "Cap" => [0x022D2], + "CapitalDifferentialD" => [0x02145], + "Cayleys" => [0x0212D], + "Ccaron" => [0x0010C], + "Ccedil" => [0x000C7], + "Ccirc" => [0x00108], + "Cconint" => [0x02230], + "Cdot" => [0x0010A], + "Cedilla" => [0x000B8], + "CenterDot" => [0x000B7], + "Cfr" => [0x0212D], + "Chi" => [0x003A7], + "CircleDot" => [0x02299], + "CircleMinus" => [0x02296], + "CirclePlus" => [0x02295], + "CircleTimes" => [0x02297], + "ClockwiseContourIntegral" => [0x02232], + "CloseCurlyDoubleQuote" => [0x0201D], + "CloseCurlyQuote" => [0x02019], + "Colon" => [0x02237], + "Colone" => [0x02A74], + "Congruent" => [0x02261], + "Conint" => [0x0222F], + "ContourIntegral" => [0x0222E], + "Copf" => [0x02102], + "Coproduct" => [0x02210], + "CounterClockwiseContourIntegral" => [0x02233], + "Cross" => [0x02A2F], + "Cscr" => [0x1D49E], + "Cup" => [0x022D3], + "CupCap" => [0x0224D], + "DD" => [0x02145], + "DDotrahd" => [0x02911], + "DJcy" => [0x00402], + "DScy" => [0x00405], + "DZcy" => [0x0040F], + "Dagger" => [0x02021], + "Darr" => [0x021A1], + "Dashv" => [0x02AE4], + "Dcaron" => [0x0010E], + "Dcy" => [0x00414], + "Del" => [0x02207], + "Delta" => [0x00394], + "Dfr" => [0x1D507], + "DiacriticalAcute" => [0x000B4], + "DiacriticalDot" => [0x002D9], + "DiacriticalDoubleAcute" => [0x002DD], + "DiacriticalGrave" => [0x00060], + "DiacriticalTilde" => [0x002DC], + "Diamond" => [0x022C4], + "DifferentialD" => [0x02146], + "Dopf" => [0x1D53B], + "Dot" => [0x000A8], + "DotDot" => [0x020DC], + "DotEqual" => [0x02250], + "DoubleContourIntegral" => [0x0222F], + "DoubleDot" => [0x000A8], + "DoubleDownArrow" => [0x021D3], + "DoubleLeftArrow" => [0x021D0], + "DoubleLeftRightArrow" => [0x021D4], + "DoubleLeftTee" => [0x02AE4], + "DoubleLongLeftArrow" => [0x027F8], + "DoubleLongLeftRightArrow" => [0x027FA], + "DoubleLongRightArrow" => [0x027F9], + "DoubleRightArrow" => [0x021D2], + "DoubleRightTee" => [0x022A8], + "DoubleUpArrow" => [0x021D1], + "DoubleUpDownArrow" => [0x021D5], + "DoubleVerticalBar" => [0x02225], + "DownArrow" => [0x02193], + "DownArrowBar" => [0x02913], + "DownArrowUpArrow" => [0x021F5], + "DownBreve" => [0x00311], + "DownLeftRightVector" => [0x02950], + "DownLeftTeeVector" => [0x0295E], + "DownLeftVector" => [0x021BD], + "DownLeftVectorBar" => [0x02956], + "DownRightTeeVector" => [0x0295F], + "DownRightVector" => [0x021C1], + "DownRightVectorBar" => [0x02957], + "DownTee" => [0x022A4], + "DownTeeArrow" => [0x021A7], + "Downarrow" => [0x021D3], + "Dscr" => [0x1D49F], + "Dstrok" => [0x00110], + "ENG" => [0x0014A], + "ETH" => [0x000D0], + "Eacute" => [0x000C9], + "Ecaron" => [0x0011A], + "Ecirc" => [0x000CA], + "Ecy" => [0x0042D], + "Edot" => [0x00116], + "Efr" => [0x1D508], + "Egrave" => [0x000C8], + "Element" => [0x02208], + "Emacr" => [0x00112], + "EmptySmallSquare" => [0x025FB], + "EmptyVerySmallSquare" => [0x025AB], + "Eogon" => [0x00118], + "Eopf" => [0x1D53C], + "Epsilon" => [0x00395], + "Equal" => [0x02A75], + "EqualTilde" => [0x02242], + "Equilibrium" => [0x021CC], + "Escr" => [0x02130], + "Esim" => [0x02A73], + "Eta" => [0x00397], + "Euml" => [0x000CB], + "Exists" => [0x02203], + "ExponentialE" => [0x02147], + "Fcy" => [0x00424], + "Ffr" => [0x1D509], + "FilledSmallSquare" => [0x025FC], + "FilledVerySmallSquare" => [0x025AA], + "Fopf" => [0x1D53D], + "ForAll" => [0x02200], + "Fouriertrf" => [0x02131], + "Fscr" => [0x02131], + "GJcy" => [0x00403], + "GT" => [0x0003E], + "Gamma" => [0x00393], + "Gammad" => [0x003DC], + "Gbreve" => [0x0011E], + "Gcedil" => [0x00122], + "Gcirc" => [0x0011C], + "Gcy" => [0x00413], + "Gdot" => [0x00120], + "Gfr" => [0x1D50A], + "Gg" => [0x022D9], + "Gopf" => [0x1D53E], + "GreaterEqual" => [0x02265], + "GreaterEqualLess" => [0x022DB], + "GreaterFullEqual" => [0x02267], + "GreaterGreater" => [0x02AA2], + "GreaterLess" => [0x02277], + "GreaterSlantEqual" => [0x02A7E], + "GreaterTilde" => [0x02273], + "Gscr" => [0x1D4A2], + "Gt" => [0x0226B], + "HARDcy" => [0x0042A], + "Hacek" => [0x002C7], + "Hat" => [0x0005E], + "Hcirc" => [0x00124], + "Hfr" => [0x0210C], + "HilbertSpace" => [0x0210B], + "Hopf" => [0x0210D], + "HorizontalLine" => [0x02500], + "Hscr" => [0x0210B], + "Hstrok" => [0x00126], + "HumpDownHump" => [0x0224E], + "HumpEqual" => [0x0224F], + "IEcy" => [0x00415], + "IJlig" => [0x00132], + "IOcy" => [0x00401], + "Iacute" => [0x000CD], + "Icirc" => [0x000CE], + "Icy" => [0x00418], + "Idot" => [0x00130], + "Ifr" => [0x02111], + "Igrave" => [0x000CC], + "Im" => [0x02111], + "Imacr" => [0x0012A], + "ImaginaryI" => [0x02148], + "Implies" => [0x021D2], + "Int" => [0x0222C], + "Integral" => [0x0222B], + "Intersection" => [0x022C2], + "InvisibleComma" => [0x02063], + "InvisibleTimes" => [0x02062], + "Iogon" => [0x0012E], + "Iopf" => [0x1D540], + "Iota" => [0x00399], + "Iscr" => [0x02110], + "Itilde" => [0x00128], + "Iukcy" => [0x00406], + "Iuml" => [0x000CF], + "Jcirc" => [0x00134], + "Jcy" => [0x00419], + "Jfr" => [0x1D50D], + "Jopf" => [0x1D541], + "Jscr" => [0x1D4A5], + "Jsercy" => [0x00408], + "Jukcy" => [0x00404], + "KHcy" => [0x00425], + "KJcy" => [0x0040C], + "Kappa" => [0x0039A], + "Kcedil" => [0x00136], + "Kcy" => [0x0041A], + "Kfr" => [0x1D50E], + "Kopf" => [0x1D542], + "Kscr" => [0x1D4A6], + "LJcy" => [0x00409], + "LT" => [0x0003C], + "Lacute" => [0x00139], + "Lambda" => [0x0039B], + "Lang" => [0x027EA], + "Laplacetrf" => [0x02112], + "Larr" => [0x0219E], + "Lcaron" => [0x0013D], + "Lcedil" => [0x0013B], + "Lcy" => [0x0041B], + "LeftAngleBracket" => [0x027E8], + "LeftArrow" => [0x02190], + "LeftArrowBar" => [0x021E4], + "LeftArrowRightArrow" => [0x021C6], + "LeftCeiling" => [0x02308], + "LeftDoubleBracket" => [0x027E6], + "LeftDownTeeVector" => [0x02961], + "LeftDownVector" => [0x021C3], + "LeftDownVectorBar" => [0x02959], + "LeftFloor" => [0x0230A], + "LeftRightArrow" => [0x02194], + "LeftRightVector" => [0x0294E], + "LeftTee" => [0x022A3], + "LeftTeeArrow" => [0x021A4], + "LeftTeeVector" => [0x0295A], + "LeftTriangle" => [0x022B2], + "LeftTriangleBar" => [0x029CF], + "LeftTriangleEqual" => [0x022B4], + "LeftUpDownVector" => [0x02951], + "LeftUpTeeVector" => [0x02960], + "LeftUpVector" => [0x021BF], + "LeftUpVectorBar" => [0x02958], + "LeftVector" => [0x021BC], + "LeftVectorBar" => [0x02952], + "Leftarrow" => [0x021D0], + "Leftrightarrow" => [0x021D4], + "LessEqualGreater" => [0x022DA], + "LessFullEqual" => [0x02266], + "LessGreater" => [0x02276], + "LessLess" => [0x02AA1], + "LessSlantEqual" => [0x02A7D], + "LessTilde" => [0x02272], + "Lfr" => [0x1D50F], + "Ll" => [0x022D8], + "Lleftarrow" => [0x021DA], + "Lmidot" => [0x0013F], + "LongLeftArrow" => [0x027F5], + "LongLeftRightArrow" => [0x027F7], + "LongRightArrow" => [0x027F6], + "Longleftarrow" => [0x027F8], + "Longleftrightarrow" => [0x027FA], + "Longrightarrow" => [0x027F9], + "Lopf" => [0x1D543], + "LowerLeftArrow" => [0x02199], + "LowerRightArrow" => [0x02198], + "Lscr" => [0x02112], + "Lsh" => [0x021B0], + "Lstrok" => [0x00141], + "Lt" => [0x0226A], + "Map" => [0x02905], + "Mcy" => [0x0041C], + "MediumSpace" => [0x0205F], + "Mellintrf" => [0x02133], + "Mfr" => [0x1D510], + "MinusPlus" => [0x02213], + "Mopf" => [0x1D544], + "Mscr" => [0x02133], + "Mu" => [0x0039C], + "NJcy" => [0x0040A], + "Nacute" => [0x00143], + "Ncaron" => [0x00147], + "Ncedil" => [0x00145], + "Ncy" => [0x0041D], + "NegativeMediumSpace" => [0x0200B], + "NegativeThickSpace" => [0x0200B], + "NegativeThinSpace" => [0x0200B], + "NegativeVeryThinSpace" => [0x0200B], + "NestedGreaterGreater" => [0x0226B], + "NestedLessLess" => [0x0226A], + "NewLine" => [0x0000A], + "Nfr" => [0x1D511], + "NoBreak" => [0x02060], + "NonBreakingSpace" => [0x000A0], + "Nopf" => [0x02115], + "Not" => [0x02AEC], + "NotCongruent" => [0x02262], + "NotCupCap" => [0x0226D], + "NotDoubleVerticalBar" => [0x02226], + "NotElement" => [0x02209], + "NotEqual" => [0x02260], + "NotEqualTilde" => [0x02242, 0x00338], + "NotExists" => [0x02204], + "NotGreater" => [0x0226F], + "NotGreaterEqual" => [0x02271], + "NotGreaterFullEqual" => [0x02267, 0x00338], + "NotGreaterGreater" => [0x0226B, 0x00338], + "NotGreaterLess" => [0x02279], + "NotGreaterSlantEqual" => [0x02A7E, 0x00338], + "NotGreaterTilde" => [0x02275], + "NotHumpDownHump" => [0x0224E, 0x00338], + "NotHumpEqual" => [0x0224F, 0x00338], + "NotLeftTriangle" => [0x022EA], + "NotLeftTriangleBar" => [0x029CF, 0x00338], + "NotLeftTriangleEqual" => [0x022EC], + "NotLess" => [0x0226E], + "NotLessEqual" => [0x02270], + "NotLessGreater" => [0x02278], + "NotLessLess" => [0x0226A, 0x00338], + "NotLessSlantEqual" => [0x02A7D, 0x00338], + "NotLessTilde" => [0x02274], + "NotNestedGreaterGreater" => [0x02AA2, 0x00338], + "NotNestedLessLess" => [0x02AA1, 0x00338], + "NotPrecedes" => [0x02280], + "NotPrecedesEqual" => [0x02AAF, 0x00338], + "NotPrecedesSlantEqual" => [0x022E0], + "NotReverseElement" => [0x0220C], + "NotRightTriangle" => [0x022EB], + "NotRightTriangleBar" => [0x029D0, 0x00338], + "NotRightTriangleEqual" => [0x022ED], + "NotSquareSubset" => [0x0228F, 0x00338], + "NotSquareSubsetEqual" => [0x022E2], + "NotSquareSuperset" => [0x02290, 0x00338], + "NotSquareSupersetEqual" => [0x022E3], + "NotSubset" => [0x02282, 0x020D2], + "NotSubsetEqual" => [0x02288], + "NotSucceeds" => [0x02281], + "NotSucceedsEqual" => [0x02AB0, 0x00338], + "NotSucceedsSlantEqual" => [0x022E1], + "NotSucceedsTilde" => [0x0227F, 0x00338], + "NotSuperset" => [0x02283, 0x020D2], + "NotSupersetEqual" => [0x02289], + "NotTilde" => [0x02241], + "NotTildeEqual" => [0x02244], + "NotTildeFullEqual" => [0x02247], + "NotTildeTilde" => [0x02249], + "NotVerticalBar" => [0x02224], + "Nscr" => [0x1D4A9], + "Ntilde" => [0x000D1], + "Nu" => [0x0039D], + "OElig" => [0x00152], + "Oacute" => [0x000D3], + "Ocirc" => [0x000D4], + "Ocy" => [0x0041E], + "Odblac" => [0x00150], + "Ofr" => [0x1D512], + "Ograve" => [0x000D2], + "Omacr" => [0x0014C], + "Omega" => [0x003A9], + "Omicron" => [0x0039F], + "Oopf" => [0x1D546], + "OpenCurlyDoubleQuote" => [0x0201C], + "OpenCurlyQuote" => [0x02018], + "Or" => [0x02A54], + "Oscr" => [0x1D4AA], + "Oslash" => [0x000D8], + "Otilde" => [0x000D5], + "Otimes" => [0x02A37], + "Ouml" => [0x000D6], + "OverBar" => [0x0203E], + "OverBrace" => [0x023DE], + "OverBracket" => [0x023B4], + "OverParenthesis" => [0x023DC], + "PartialD" => [0x02202], + "Pcy" => [0x0041F], + "Pfr" => [0x1D513], + "Phi" => [0x003A6], + "Pi" => [0x003A0], + "PlusMinus" => [0x000B1], + "Poincareplane" => [0x0210C], + "Popf" => [0x02119], + "Pr" => [0x02ABB], + "Precedes" => [0x0227A], + "PrecedesEqual" => [0x02AAF], + "PrecedesSlantEqual" => [0x0227C], + "PrecedesTilde" => [0x0227E], + "Prime" => [0x02033], + "Product" => [0x0220F], + "Proportion" => [0x02237], + "Proportional" => [0x0221D], + "Pscr" => [0x1D4AB], + "Psi" => [0x003A8], + "QUOT" => [0x00022], + "Qfr" => [0x1D514], + "Qopf" => [0x0211A], + "Qscr" => [0x1D4AC], + "RBarr" => [0x02910], + "REG" => [0x000AE], + "Racute" => [0x00154], + "Rang" => [0x027EB], + "Rarr" => [0x021A0], + "Rarrtl" => [0x02916], + "Rcaron" => [0x00158], + "Rcedil" => [0x00156], + "Rcy" => [0x00420], + "Re" => [0x0211C], + "ReverseElement" => [0x0220B], + "ReverseEquilibrium" => [0x021CB], + "ReverseUpEquilibrium" => [0x0296F], + "Rfr" => [0x0211C], + "Rho" => [0x003A1], + "RightAngleBracket" => [0x027E9], + "RightArrow" => [0x02192], + "RightArrowBar" => [0x021E5], + "RightArrowLeftArrow" => [0x021C4], + "RightCeiling" => [0x02309], + "RightDoubleBracket" => [0x027E7], + "RightDownTeeVector" => [0x0295D], + "RightDownVector" => [0x021C2], + "RightDownVectorBar" => [0x02955], + "RightFloor" => [0x0230B], + "RightTee" => [0x022A2], + "RightTeeArrow" => [0x021A6], + "RightTeeVector" => [0x0295B], + "RightTriangle" => [0x022B3], + "RightTriangleBar" => [0x029D0], + "RightTriangleEqual" => [0x022B5], + "RightUpDownVector" => [0x0294F], + "RightUpTeeVector" => [0x0295C], + "RightUpVector" => [0x021BE], + "RightUpVectorBar" => [0x02954], + "RightVector" => [0x021C0], + "RightVectorBar" => [0x02953], + "Rightarrow" => [0x021D2], + "Ropf" => [0x0211D], + "RoundImplies" => [0x02970], + "Rrightarrow" => [0x021DB], + "Rscr" => [0x0211B], + "Rsh" => [0x021B1], + "RuleDelayed" => [0x029F4], + "SHCHcy" => [0x00429], + "SHcy" => [0x00428], + "SOFTcy" => [0x0042C], + "Sacute" => [0x0015A], + "Sc" => [0x02ABC], + "Scaron" => [0x00160], + "Scedil" => [0x0015E], + "Scirc" => [0x0015C], + "Scy" => [0x00421], + "Sfr" => [0x1D516], + "ShortDownArrow" => [0x02193], + "ShortLeftArrow" => [0x02190], + "ShortRightArrow" => [0x02192], + "ShortUpArrow" => [0x02191], + "Sigma" => [0x003A3], + "SmallCircle" => [0x02218], + "Sopf" => [0x1D54A], + "Sqrt" => [0x0221A], + "Square" => [0x025A1], + "SquareIntersection" => [0x02293], + "SquareSubset" => [0x0228F], + "SquareSubsetEqual" => [0x02291], + "SquareSuperset" => [0x02290], + "SquareSupersetEqual" => [0x02292], + "SquareUnion" => [0x02294], + "Sscr" => [0x1D4AE], + "Star" => [0x022C6], + "Sub" => [0x022D0], + "Subset" => [0x022D0], + "SubsetEqual" => [0x02286], + "Succeeds" => [0x0227B], + "SucceedsEqual" => [0x02AB0], + "SucceedsSlantEqual" => [0x0227D], + "SucceedsTilde" => [0x0227F], + "SuchThat" => [0x0220B], + "Sum" => [0x02211], + "Sup" => [0x022D1], + "Superset" => [0x02283], + "SupersetEqual" => [0x02287], + "Supset" => [0x022D1], + "THORN" => [0x000DE], + "TRADE" => [0x02122], + "TSHcy" => [0x0040B], + "TScy" => [0x00426], + "Tab" => [0x00009], + "Tau" => [0x003A4], + "Tcaron" => [0x00164], + "Tcedil" => [0x00162], + "Tcy" => [0x00422], + "Tfr" => [0x1D517], + "Therefore" => [0x02234], + "Theta" => [0x00398], + "ThickSpace" => [0x0205F, 0x0200A], + "ThinSpace" => [0x02009], + "Tilde" => [0x0223C], + "TildeEqual" => [0x02243], + "TildeFullEqual" => [0x02245], + "TildeTilde" => [0x02248], + "Topf" => [0x1D54B], + "TripleDot" => [0x020DB], + "Tscr" => [0x1D4AF], + "Tstrok" => [0x00166], + "Uacute" => [0x000DA], + "Uarr" => [0x0219F], + "Uarrocir" => [0x02949], + "Ubrcy" => [0x0040E], + "Ubreve" => [0x0016C], + "Ucirc" => [0x000DB], + "Ucy" => [0x00423], + "Udblac" => [0x00170], + "Ufr" => [0x1D518], + "Ugrave" => [0x000D9], + "Umacr" => [0x0016A], + "UnderBar" => [0x0005F], + "UnderBrace" => [0x023DF], + "UnderBracket" => [0x023B5], + "UnderParenthesis" => [0x023DD], + "Union" => [0x022C3], + "UnionPlus" => [0x0228E], + "Uogon" => [0x00172], + "Uopf" => [0x1D54C], + "UpArrow" => [0x02191], + "UpArrowBar" => [0x02912], + "UpArrowDownArrow" => [0x021C5], + "UpDownArrow" => [0x02195], + "UpEquilibrium" => [0x0296E], + "UpTee" => [0x022A5], + "UpTeeArrow" => [0x021A5], + "Uparrow" => [0x021D1], + "Updownarrow" => [0x021D5], + "UpperLeftArrow" => [0x02196], + "UpperRightArrow" => [0x02197], + "Upsi" => [0x003D2], + "Upsilon" => [0x003A5], + "Uring" => [0x0016E], + "Uscr" => [0x1D4B0], + "Utilde" => [0x00168], + "Uuml" => [0x000DC], + "VDash" => [0x022AB], + "Vbar" => [0x02AEB], + "Vcy" => [0x00412], + "Vdash" => [0x022A9], + "Vdashl" => [0x02AE6], + "Vee" => [0x022C1], + "Verbar" => [0x02016], + "Vert" => [0x02016], + "VerticalBar" => [0x02223], + "VerticalLine" => [0x0007C], + "VerticalSeparator" => [0x02758], + "VerticalTilde" => [0x02240], + "VeryThinSpace" => [0x0200A], + "Vfr" => [0x1D519], + "Vopf" => [0x1D54D], + "Vscr" => [0x1D4B1], + "Vvdash" => [0x022AA], + "Wcirc" => [0x00174], + "Wedge" => [0x022C0], + "Wfr" => [0x1D51A], + "Wopf" => [0x1D54E], + "Wscr" => [0x1D4B2], + "Xfr" => [0x1D51B], + "Xi" => [0x0039E], + "Xopf" => [0x1D54F], + "Xscr" => [0x1D4B3], + "YAcy" => [0x0042F], + "YIcy" => [0x00407], + "YUcy" => [0x0042E], + "Yacute" => [0x000DD], + "Ycirc" => [0x00176], + "Ycy" => [0x0042B], + "Yfr" => [0x1D51C], + "Yopf" => [0x1D550], + "Yscr" => [0x1D4B4], + "Yuml" => [0x00178], + "ZHcy" => [0x00416], + "Zacute" => [0x00179], + "Zcaron" => [0x0017D], + "Zcy" => [0x00417], + "Zdot" => [0x0017B], + "ZeroWidthSpace" => [0x0200B], + "Zeta" => [0x00396], + "Zfr" => [0x02128], + "Zopf" => [0x02124], + "Zscr" => [0x1D4B5], + "aacute" => [0x000E1], + "abreve" => [0x00103], + "ac" => [0x0223E], + "acE" => [0x0223E, 0x00333], + "acd" => [0x0223F], + "acirc" => [0x000E2], + "acute" => [0x000B4], + "acy" => [0x00430], + "aelig" => [0x000E6], + "af" => [0x02061], + "afr" => [0x1D51E], + "agrave" => [0x000E0], + "alefsym" => [0x02135], + "aleph" => [0x02135], + "alpha" => [0x003B1], + "amacr" => [0x00101], + "amalg" => [0x02A3F], + "amp" => [0x00026], + "and" => [0x02227], + "andand" => [0x02A55], + "andd" => [0x02A5C], + "andslope" => [0x02A58], + "andv" => [0x02A5A], + "ang" => [0x02220], + "ange" => [0x029A4], + "angle" => [0x02220], + "angmsd" => [0x02221], + "angmsdaa" => [0x029A8], + "angmsdab" => [0x029A9], + "angmsdac" => [0x029AA], + "angmsdad" => [0x029AB], + "angmsdae" => [0x029AC], + "angmsdaf" => [0x029AD], + "angmsdag" => [0x029AE], + "angmsdah" => [0x029AF], + "angrt" => [0x0221F], + "angrtvb" => [0x022BE], + "angrtvbd" => [0x0299D], + "angsph" => [0x02222], + "angst" => [0x000C5], + "angzarr" => [0x0237C], + "aogon" => [0x00105], + "aopf" => [0x1D552], + "ap" => [0x02248], + "apE" => [0x02A70], + "apacir" => [0x02A6F], + "ape" => [0x0224A], + "apid" => [0x0224B], + "apos" => [0x00027], + "approx" => [0x02248], + "approxeq" => [0x0224A], + "aring" => [0x000E5], + "ascr" => [0x1D4B6], + "ast" => [0x0002A], + "asymp" => [0x02248], + "asympeq" => [0x0224D], + "atilde" => [0x000E3], + "auml" => [0x000E4], + "awconint" => [0x02233], + "awint" => [0x02A11], + "bNot" => [0x02AED], + "backcong" => [0x0224C], + "backepsilon" => [0x003F6], + "backprime" => [0x02035], + "backsim" => [0x0223D], + "backsimeq" => [0x022CD], + "barvee" => [0x022BD], + "barwed" => [0x02305], + "barwedge" => [0x02305], + "bbrk" => [0x023B5], + "bbrktbrk" => [0x023B6], + "bcong" => [0x0224C], + "bcy" => [0x00431], + "bdquo" => [0x0201E], + "becaus" => [0x02235], + "because" => [0x02235], + "bemptyv" => [0x029B0], + "bepsi" => [0x003F6], + "bernou" => [0x0212C], + "beta" => [0x003B2], + "beth" => [0x02136], + "between" => [0x0226C], + "bfr" => [0x1D51F], + "bigcap" => [0x022C2], + "bigcirc" => [0x025EF], + "bigcup" => [0x022C3], + "bigodot" => [0x02A00], + "bigoplus" => [0x02A01], + "bigotimes" => [0x02A02], + "bigsqcup" => [0x02A06], + "bigstar" => [0x02605], + "bigtriangledown" => [0x025BD], + "bigtriangleup" => [0x025B3], + "biguplus" => [0x02A04], + "bigvee" => [0x022C1], + "bigwedge" => [0x022C0], + "bkarow" => [0x0290D], + "blacklozenge" => [0x029EB], + "blacksquare" => [0x025AA], + "blacktriangle" => [0x025B4], + "blacktriangledown" => [0x025BE], + "blacktriangleleft" => [0x025C2], + "blacktriangleright" => [0x025B8], + "blank" => [0x02423], + "blk12" => [0x02592], + "blk14" => [0x02591], + "blk34" => [0x02593], + "block" => [0x02588], + "bne" => [0x0003D, 0x020E5], + "bnequiv" => [0x02261, 0x020E5], + "bnot" => [0x02310], + "bopf" => [0x1D553], + "bot" => [0x022A5], + "bottom" => [0x022A5], + "bowtie" => [0x022C8], + "boxDL" => [0x02557], + "boxDR" => [0x02554], + "boxDl" => [0x02556], + "boxDr" => [0x02553], + "boxH" => [0x02550], + "boxHD" => [0x02566], + "boxHU" => [0x02569], + "boxHd" => [0x02564], + "boxHu" => [0x02567], + "boxUL" => [0x0255D], + "boxUR" => [0x0255A], + "boxUl" => [0x0255C], + "boxUr" => [0x02559], + "boxV" => [0x02551], + "boxVH" => [0x0256C], + "boxVL" => [0x02563], + "boxVR" => [0x02560], + "boxVh" => [0x0256B], + "boxVl" => [0x02562], + "boxVr" => [0x0255F], + "boxbox" => [0x029C9], + "boxdL" => [0x02555], + "boxdR" => [0x02552], + "boxdl" => [0x02510], + "boxdr" => [0x0250C], + "boxh" => [0x02500], + "boxhD" => [0x02565], + "boxhU" => [0x02568], + "boxhd" => [0x0252C], + "boxhu" => [0x02534], + "boxminus" => [0x0229F], + "boxplus" => [0x0229E], + "boxtimes" => [0x022A0], + "boxuL" => [0x0255B], + "boxuR" => [0x02558], + "boxul" => [0x02518], + "boxur" => [0x02514], + "boxv" => [0x02502], + "boxvH" => [0x0256A], + "boxvL" => [0x02561], + "boxvR" => [0x0255E], + "boxvh" => [0x0253C], + "boxvl" => [0x02524], + "boxvr" => [0x0251C], + "bprime" => [0x02035], + "breve" => [0x002D8], + "brvbar" => [0x000A6], + "bscr" => [0x1D4B7], + "bsemi" => [0x0204F], + "bsim" => [0x0223D], + "bsime" => [0x022CD], + "bsol" => [0x0005C], + "bsolb" => [0x029C5], + "bsolhsub" => [0x027C8], + "bull" => [0x02022], + "bullet" => [0x02022], + "bump" => [0x0224E], + "bumpE" => [0x02AAE], + "bumpe" => [0x0224F], + "bumpeq" => [0x0224F], + "cacute" => [0x00107], + "cap" => [0x02229], + "capand" => [0x02A44], + "capbrcup" => [0x02A49], + "capcap" => [0x02A4B], + "capcup" => [0x02A47], + "capdot" => [0x02A40], + "caps" => [0x02229, 0x0FE00], + "caret" => [0x02041], + "caron" => [0x002C7], + "ccaps" => [0x02A4D], + "ccaron" => [0x0010D], + "ccedil" => [0x000E7], + "ccirc" => [0x00109], + "ccups" => [0x02A4C], + "ccupssm" => [0x02A50], + "cdot" => [0x0010B], + "cedil" => [0x000B8], + "cemptyv" => [0x029B2], + "cent" => [0x000A2], + "centerdot" => [0x000B7], + "cfr" => [0x1D520], + "chcy" => [0x00447], + "check" => [0x02713], + "checkmark" => [0x02713], + "chi" => [0x003C7], + "cir" => [0x025CB], + "cirE" => [0x029C3], + "circ" => [0x002C6], + "circeq" => [0x02257], + "circlearrowleft" => [0x021BA], + "circlearrowright" => [0x021BB], + "circledR" => [0x000AE], + "circledS" => [0x024C8], + "circledast" => [0x0229B], + "circledcirc" => [0x0229A], + "circleddash" => [0x0229D], + "cire" => [0x02257], + "cirfnint" => [0x02A10], + "cirmid" => [0x02AEF], + "cirscir" => [0x029C2], + "clubs" => [0x02663], + "clubsuit" => [0x02663], + "colon" => [0x0003A], + "colone" => [0x02254], + "coloneq" => [0x02254], + "comma" => [0x0002C], + "commat" => [0x00040], + "comp" => [0x02201], + "compfn" => [0x02218], + "complement" => [0x02201], + "complexes" => [0x02102], + "cong" => [0x02245], + "congdot" => [0x02A6D], + "conint" => [0x0222E], + "copf" => [0x1D554], + "coprod" => [0x02210], + "copy" => [0x000A9], + "copysr" => [0x02117], + "crarr" => [0x021B5], + "cross" => [0x02717], + "cscr" => [0x1D4B8], + "csub" => [0x02ACF], + "csube" => [0x02AD1], + "csup" => [0x02AD0], + "csupe" => [0x02AD2], + "ctdot" => [0x022EF], + "cudarrl" => [0x02938], + "cudarrr" => [0x02935], + "cuepr" => [0x022DE], + "cuesc" => [0x022DF], + "cularr" => [0x021B6], + "cularrp" => [0x0293D], + "cup" => [0x0222A], + "cupbrcap" => [0x02A48], + "cupcap" => [0x02A46], + "cupcup" => [0x02A4A], + "cupdot" => [0x0228D], + "cupor" => [0x02A45], + "cups" => [0x0222A, 0x0FE00], + "curarr" => [0x021B7], + "curarrm" => [0x0293C], + "curlyeqprec" => [0x022DE], + "curlyeqsucc" => [0x022DF], + "curlyvee" => [0x022CE], + "curlywedge" => [0x022CF], + "curren" => [0x000A4], + "curvearrowleft" => [0x021B6], + "curvearrowright" => [0x021B7], + "cuvee" => [0x022CE], + "cuwed" => [0x022CF], + "cwconint" => [0x02232], + "cwint" => [0x02231], + "cylcty" => [0x0232D], + "dArr" => [0x021D3], + "dHar" => [0x02965], + "dagger" => [0x02020], + "daleth" => [0x02138], + "darr" => [0x02193], + "dash" => [0x02010], + "dashv" => [0x022A3], + "dbkarow" => [0x0290F], + "dblac" => [0x002DD], + "dcaron" => [0x0010F], + "dcy" => [0x00434], + "dd" => [0x02146], + "ddagger" => [0x02021], + "ddarr" => [0x021CA], + "ddotseq" => [0x02A77], + "deg" => [0x000B0], + "delta" => [0x003B4], + "demptyv" => [0x029B1], + "dfisht" => [0x0297F], + "dfr" => [0x1D521], + "dharl" => [0x021C3], + "dharr" => [0x021C2], + "diam" => [0x022C4], + "diamond" => [0x022C4], + "diamondsuit" => [0x02666], + "diams" => [0x02666], + "die" => [0x000A8], + "digamma" => [0x003DD], + "disin" => [0x022F2], + "div" => [0x000F7], + "divide" => [0x000F7], + "divideontimes" => [0x022C7], + "divonx" => [0x022C7], + "djcy" => [0x00452], + "dlcorn" => [0x0231E], + "dlcrop" => [0x0230D], + "dollar" => [0x00024], + "dopf" => [0x1D555], + "dot" => [0x002D9], + "doteq" => [0x02250], + "doteqdot" => [0x02251], + "dotminus" => [0x02238], + "dotplus" => [0x02214], + "dotsquare" => [0x022A1], + "doublebarwedge" => [0x02306], + "downarrow" => [0x02193], + "downdownarrows" => [0x021CA], + "downharpoonleft" => [0x021C3], + "downharpoonright" => [0x021C2], + "drbkarow" => [0x02910], + "drcorn" => [0x0231F], + "drcrop" => [0x0230C], + "dscr" => [0x1D4B9], + "dscy" => [0x00455], + "dsol" => [0x029F6], + "dstrok" => [0x00111], + "dtdot" => [0x022F1], + "dtri" => [0x025BF], + "dtrif" => [0x025BE], + "duarr" => [0x021F5], + "duhar" => [0x0296F], + "dwangle" => [0x029A6], + "dzcy" => [0x0045F], + "dzigrarr" => [0x027FF], + "eDDot" => [0x02A77], + "eDot" => [0x02251], + "eacute" => [0x000E9], + "easter" => [0x02A6E], + "ecaron" => [0x0011B], + "ecir" => [0x02256], + "ecirc" => [0x000EA], + "ecolon" => [0x02255], + "ecy" => [0x0044D], + "edot" => [0x00117], + "ee" => [0x02147], + "efDot" => [0x02252], + "efr" => [0x1D522], + "eg" => [0x02A9A], + "egrave" => [0x000E8], + "egs" => [0x02A96], + "egsdot" => [0x02A98], + "el" => [0x02A99], + "elinters" => [0x023E7], + "ell" => [0x02113], + "els" => [0x02A95], + "elsdot" => [0x02A97], + "emacr" => [0x00113], + "empty" => [0x02205], + "emptyset" => [0x02205], + "emptyv" => [0x02205], + "emsp" => [0x02003], + "emsp13" => [0x02004], + "emsp14" => [0x02005], + "eng" => [0x0014B], + "ensp" => [0x02002], + "eogon" => [0x00119], + "eopf" => [0x1D556], + "epar" => [0x022D5], + "eparsl" => [0x029E3], + "eplus" => [0x02A71], + "epsi" => [0x003B5], + "epsilon" => [0x003B5], + "epsiv" => [0x003F5], + "eqcirc" => [0x02256], + "eqcolon" => [0x02255], + "eqsim" => [0x02242], + "eqslantgtr" => [0x02A96], + "eqslantless" => [0x02A95], + "equals" => [0x0003D], + "equest" => [0x0225F], + "equiv" => [0x02261], + "equivDD" => [0x02A78], + "eqvparsl" => [0x029E5], + "erDot" => [0x02253], + "erarr" => [0x02971], + "escr" => [0x0212F], + "esdot" => [0x02250], + "esim" => [0x02242], + "eta" => [0x003B7], + "eth" => [0x000F0], + "euml" => [0x000EB], + "euro" => [0x020AC], + "excl" => [0x00021], + "exist" => [0x02203], + "expectation" => [0x02130], + "exponentiale" => [0x02147], + "fallingdotseq" => [0x02252], + "fcy" => [0x00444], + "female" => [0x02640], + "ffilig" => [0x0FB03], + "fflig" => [0x0FB00], + "ffllig" => [0x0FB04], + "ffr" => [0x1D523], + "filig" => [0x0FB01], + "fjlig" => [0x00066, 0x0006A], + "flat" => [0x0266D], + "fllig" => [0x0FB02], + "fltns" => [0x025B1], + "fnof" => [0x00192], + "fopf" => [0x1D557], + "forall" => [0x02200], + "fork" => [0x022D4], + "forkv" => [0x02AD9], + "fpartint" => [0x02A0D], + "frac12" => [0x000BD], + "frac13" => [0x02153], + "frac14" => [0x000BC], + "frac15" => [0x02155], + "frac16" => [0x02159], + "frac18" => [0x0215B], + "frac23" => [0x02154], + "frac25" => [0x02156], + "frac34" => [0x000BE], + "frac35" => [0x02157], + "frac38" => [0x0215C], + "frac45" => [0x02158], + "frac56" => [0x0215A], + "frac58" => [0x0215D], + "frac78" => [0x0215E], + "frasl" => [0x02044], + "frown" => [0x02322], + "fscr" => [0x1D4BB], + "gE" => [0x02267], + "gEl" => [0x02A8C], + "gacute" => [0x001F5], + "gamma" => [0x003B3], + "gammad" => [0x003DD], + "gap" => [0x02A86], + "gbreve" => [0x0011F], + "gcirc" => [0x0011D], + "gcy" => [0x00433], + "gdot" => [0x00121], + "ge" => [0x02265], + "gel" => [0x022DB], + "geq" => [0x02265], + "geqq" => [0x02267], + "geqslant" => [0x02A7E], + "ges" => [0x02A7E], + "gescc" => [0x02AA9], + "gesdot" => [0x02A80], + "gesdoto" => [0x02A82], + "gesdotol" => [0x02A84], + "gesl" => [0x022DB, 0x0FE00], + "gesles" => [0x02A94], + "gfr" => [0x1D524], + "gg" => [0x0226B], + "ggg" => [0x022D9], + "gimel" => [0x02137], + "gjcy" => [0x00453], + "gl" => [0x02277], + "glE" => [0x02A92], + "gla" => [0x02AA5], + "glj" => [0x02AA4], + "gnE" => [0x02269], + "gnap" => [0x02A8A], + "gnapprox" => [0x02A8A], + "gne" => [0x02A88], + "gneq" => [0x02A88], + "gneqq" => [0x02269], + "gnsim" => [0x022E7], + "gopf" => [0x1D558], + "grave" => [0x00060], + "gscr" => [0x0210A], + "gsim" => [0x02273], + "gsime" => [0x02A8E], + "gsiml" => [0x02A90], + "gt" => [0x0003E], + "gtcc" => [0x02AA7], + "gtcir" => [0x02A7A], + "gtdot" => [0x022D7], + "gtlPar" => [0x02995], + "gtquest" => [0x02A7C], + "gtrapprox" => [0x02A86], + "gtrarr" => [0x02978], + "gtrdot" => [0x022D7], + "gtreqless" => [0x022DB], + "gtreqqless" => [0x02A8C], + "gtrless" => [0x02277], + "gtrsim" => [0x02273], + "gvertneqq" => [0x02269, 0x0FE00], + "gvnE" => [0x02269, 0x0FE00], + "hArr" => [0x021D4], + "hairsp" => [0x0200A], + "half" => [0x000BD], + "hamilt" => [0x0210B], + "hardcy" => [0x0044A], + "harr" => [0x02194], + "harrcir" => [0x02948], + "harrw" => [0x021AD], + "hbar" => [0x0210F], + "hcirc" => [0x00125], + "hearts" => [0x02665], + "heartsuit" => [0x02665], + "hellip" => [0x02026], + "hercon" => [0x022B9], + "hfr" => [0x1D525], + "hksearow" => [0x02925], + "hkswarow" => [0x02926], + "hoarr" => [0x021FF], + "homtht" => [0x0223B], + "hookleftarrow" => [0x021A9], + "hookrightarrow" => [0x021AA], + "hopf" => [0x1D559], + "horbar" => [0x02015], + "hscr" => [0x1D4BD], + "hslash" => [0x0210F], + "hstrok" => [0x00127], + "hybull" => [0x02043], + "hyphen" => [0x02010], + "iacute" => [0x000ED], + "ic" => [0x02063], + "icirc" => [0x000EE], + "icy" => [0x00438], + "iecy" => [0x00435], + "iexcl" => [0x000A1], + "iff" => [0x021D4], + "ifr" => [0x1D526], + "igrave" => [0x000EC], + "ii" => [0x02148], + "iiiint" => [0x02A0C], + "iiint" => [0x0222D], + "iinfin" => [0x029DC], + "iiota" => [0x02129], + "ijlig" => [0x00133], + "imacr" => [0x0012B], + "image" => [0x02111], + "imagline" => [0x02110], + "imagpart" => [0x02111], + "imath" => [0x00131], + "imof" => [0x022B7], + "imped" => [0x001B5], + "in" => [0x02208], + "incare" => [0x02105], + "infin" => [0x0221E], + "infintie" => [0x029DD], + "inodot" => [0x00131], + "int" => [0x0222B], + "intcal" => [0x022BA], + "integers" => [0x02124], + "intercal" => [0x022BA], + "intlarhk" => [0x02A17], + "intprod" => [0x02A3C], + "iocy" => [0x00451], + "iogon" => [0x0012F], + "iopf" => [0x1D55A], + "iota" => [0x003B9], + "iprod" => [0x02A3C], + "iquest" => [0x000BF], + "iscr" => [0x1D4BE], + "isin" => [0x02208], + "isinE" => [0x022F9], + "isindot" => [0x022F5], + "isins" => [0x022F4], + "isinsv" => [0x022F3], + "isinv" => [0x02208], + "it" => [0x02062], + "itilde" => [0x00129], + "iukcy" => [0x00456], + "iuml" => [0x000EF], + "jcirc" => [0x00135], + "jcy" => [0x00439], + "jfr" => [0x1D527], + "jmath" => [0x00237], + "jopf" => [0x1D55B], + "jscr" => [0x1D4BF], + "jsercy" => [0x00458], + "jukcy" => [0x00454], + "kappa" => [0x003BA], + "kappav" => [0x003F0], + "kcedil" => [0x00137], + "kcy" => [0x0043A], + "kfr" => [0x1D528], + "kgreen" => [0x00138], + "khcy" => [0x00445], + "kjcy" => [0x0045C], + "kopf" => [0x1D55C], + "kscr" => [0x1D4C0], + "lAarr" => [0x021DA], + "lArr" => [0x021D0], + "lAtail" => [0x0291B], + "lBarr" => [0x0290E], + "lE" => [0x02266], + "lEg" => [0x02A8B], + "lHar" => [0x02962], + "lacute" => [0x0013A], + "laemptyv" => [0x029B4], + "lagran" => [0x02112], + "lambda" => [0x003BB], + "lang" => [0x027E8], + "langd" => [0x02991], + "langle" => [0x027E8], + "lap" => [0x02A85], + "laquo" => [0x000AB], + "larr" => [0x02190], + "larrb" => [0x021E4], + "larrbfs" => [0x0291F], + "larrfs" => [0x0291D], + "larrhk" => [0x021A9], + "larrlp" => [0x021AB], + "larrpl" => [0x02939], + "larrsim" => [0x02973], + "larrtl" => [0x021A2], + "lat" => [0x02AAB], + "latail" => [0x02919], + "late" => [0x02AAD], + "lates" => [0x02AAD, 0x0FE00], + "lbarr" => [0x0290C], + "lbbrk" => [0x02772], + "lbrace" => [0x0007B], + "lbrack" => [0x0005B], + "lbrke" => [0x0298B], + "lbrksld" => [0x0298F], + "lbrkslu" => [0x0298D], + "lcaron" => [0x0013E], + "lcedil" => [0x0013C], + "lceil" => [0x02308], + "lcub" => [0x0007B], + "lcy" => [0x0043B], + "ldca" => [0x02936], + "ldquo" => [0x0201C], + "ldquor" => [0x0201E], + "ldrdhar" => [0x02967], + "ldrushar" => [0x0294B], + "ldsh" => [0x021B2], + "le" => [0x02264], + "leftarrow" => [0x02190], + "leftarrowtail" => [0x021A2], + "leftharpoondown" => [0x021BD], + "leftharpoonup" => [0x021BC], + "leftleftarrows" => [0x021C7], + "leftrightarrow" => [0x02194], + "leftrightarrows" => [0x021C6], + "leftrightharpoons" => [0x021CB], + "leftrightsquigarrow" => [0x021AD], + "leftthreetimes" => [0x022CB], + "leg" => [0x022DA], + "leq" => [0x02264], + "leqq" => [0x02266], + "leqslant" => [0x02A7D], + "les" => [0x02A7D], + "lescc" => [0x02AA8], + "lesdot" => [0x02A7F], + "lesdoto" => [0x02A81], + "lesdotor" => [0x02A83], + "lesg" => [0x022DA, 0x0FE00], + "lesges" => [0x02A93], + "lessapprox" => [0x02A85], + "lessdot" => [0x022D6], + "lesseqgtr" => [0x022DA], + "lesseqqgtr" => [0x02A8B], + "lessgtr" => [0x02276], + "lesssim" => [0x02272], + "lfisht" => [0x0297C], + "lfloor" => [0x0230A], + "lfr" => [0x1D529], + "lg" => [0x02276], + "lgE" => [0x02A91], + "lhard" => [0x021BD], + "lharu" => [0x021BC], + "lharul" => [0x0296A], + "lhblk" => [0x02584], + "ljcy" => [0x00459], + "ll" => [0x0226A], + "llarr" => [0x021C7], + "llcorner" => [0x0231E], + "llhard" => [0x0296B], + "lltri" => [0x025FA], + "lmidot" => [0x00140], + "lmoust" => [0x023B0], + "lmoustache" => [0x023B0], + "lnE" => [0x02268], + "lnap" => [0x02A89], + "lnapprox" => [0x02A89], + "lne" => [0x02A87], + "lneq" => [0x02A87], + "lneqq" => [0x02268], + "lnsim" => [0x022E6], + "loang" => [0x027EC], + "loarr" => [0x021FD], + "lobrk" => [0x027E6], + "longleftarrow" => [0x027F5], + "longleftrightarrow" => [0x027F7], + "longmapsto" => [0x027FC], + "longrightarrow" => [0x027F6], + "looparrowleft" => [0x021AB], + "looparrowright" => [0x021AC], + "lopar" => [0x02985], + "lopf" => [0x1D55D], + "loplus" => [0x02A2D], + "lotimes" => [0x02A34], + "lowast" => [0x02217], + "lowbar" => [0x0005F], + "loz" => [0x025CA], + "lozenge" => [0x025CA], + "lozf" => [0x029EB], + "lpar" => [0x00028], + "lparlt" => [0x02993], + "lrarr" => [0x021C6], + "lrcorner" => [0x0231F], + "lrhar" => [0x021CB], + "lrhard" => [0x0296D], + "lrm" => [0x0200E], + "lrtri" => [0x022BF], + "lsaquo" => [0x02039], + "lscr" => [0x1D4C1], + "lsh" => [0x021B0], + "lsim" => [0x02272], + "lsime" => [0x02A8D], + "lsimg" => [0x02A8F], + "lsqb" => [0x0005B], + "lsquo" => [0x02018], + "lsquor" => [0x0201A], + "lstrok" => [0x00142], + "lt" => [0x0003C], + "ltcc" => [0x02AA6], + "ltcir" => [0x02A79], + "ltdot" => [0x022D6], + "lthree" => [0x022CB], + "ltimes" => [0x022C9], + "ltlarr" => [0x02976], + "ltquest" => [0x02A7B], + "ltrPar" => [0x02996], + "ltri" => [0x025C3], + "ltrie" => [0x022B4], + "ltrif" => [0x025C2], + "lurdshar" => [0x0294A], + "luruhar" => [0x02966], + "lvertneqq" => [0x02268, 0x0FE00], + "lvnE" => [0x02268, 0x0FE00], + "mDDot" => [0x0223A], + "macr" => [0x000AF], + "male" => [0x02642], + "malt" => [0x02720], + "maltese" => [0x02720], + "map" => [0x021A6], + "mapsto" => [0x021A6], + "mapstodown" => [0x021A7], + "mapstoleft" => [0x021A4], + "mapstoup" => [0x021A5], + "marker" => [0x025AE], + "mcomma" => [0x02A29], + "mcy" => [0x0043C], + "mdash" => [0x02014], + "measuredangle" => [0x02221], + "mfr" => [0x1D52A], + "mho" => [0x02127], + "micro" => [0x000B5], + "mid" => [0x02223], + "midast" => [0x0002A], + "midcir" => [0x02AF0], + "middot" => [0x000B7], + "minus" => [0x02212], + "minusb" => [0x0229F], + "minusd" => [0x02238], + "minusdu" => [0x02A2A], + "mlcp" => [0x02ADB], + "mldr" => [0x02026], + "mnplus" => [0x02213], + "models" => [0x022A7], + "mopf" => [0x1D55E], + "mp" => [0x02213], + "mscr" => [0x1D4C2], + "mstpos" => [0x0223E], + "mu" => [0x003BC], + "multimap" => [0x022B8], + "mumap" => [0x022B8], + "nGg" => [0x022D9, 0x00338], + "nGt" => [0x0226B, 0x020D2], + "nGtv" => [0x0226B, 0x00338], + "nLeftarrow" => [0x021CD], + "nLeftrightarrow" => [0x021CE], + "nLl" => [0x022D8, 0x00338], + "nLt" => [0x0226A, 0x020D2], + "nLtv" => [0x0226A, 0x00338], + "nRightarrow" => [0x021CF], + "nVDash" => [0x022AF], + "nVdash" => [0x022AE], + "nabla" => [0x02207], + "nacute" => [0x00144], + "nang" => [0x02220, 0x020D2], + "nap" => [0x02249], + "napE" => [0x02A70, 0x00338], + "napid" => [0x0224B, 0x00338], + "napos" => [0x00149], + "napprox" => [0x02249], + "natur" => [0x0266E], + "natural" => [0x0266E], + "naturals" => [0x02115], + "nbsp" => [0x000A0], + "nbump" => [0x0224E, 0x00338], + "nbumpe" => [0x0224F, 0x00338], + "ncap" => [0x02A43], + "ncaron" => [0x00148], + "ncedil" => [0x00146], + "ncong" => [0x02247], + "ncongdot" => [0x02A6D, 0x00338], + "ncup" => [0x02A42], + "ncy" => [0x0043D], + "ndash" => [0x02013], + "ne" => [0x02260], + "neArr" => [0x021D7], + "nearhk" => [0x02924], + "nearr" => [0x02197], + "nearrow" => [0x02197], + "nedot" => [0x02250, 0x00338], + "nequiv" => [0x02262], + "nesear" => [0x02928], + "nesim" => [0x02242, 0x00338], + "nexist" => [0x02204], + "nexists" => [0x02204], + "nfr" => [0x1D52B], + "ngE" => [0x02267, 0x00338], + "nge" => [0x02271], + "ngeq" => [0x02271], + "ngeqq" => [0x02267, 0x00338], + "ngeqslant" => [0x02A7E, 0x00338], + "nges" => [0x02A7E, 0x00338], + "ngsim" => [0x02275], + "ngt" => [0x0226F], + "ngtr" => [0x0226F], + "nhArr" => [0x021CE], + "nharr" => [0x021AE], + "nhpar" => [0x02AF2], + "ni" => [0x0220B], + "nis" => [0x022FC], + "nisd" => [0x022FA], + "niv" => [0x0220B], + "njcy" => [0x0045A], + "nlArr" => [0x021CD], + "nlE" => [0x02266, 0x00338], + "nlarr" => [0x0219A], + "nldr" => [0x02025], + "nle" => [0x02270], + "nleftarrow" => [0x0219A], + "nleftrightarrow" => [0x021AE], + "nleq" => [0x02270], + "nleqq" => [0x02266, 0x00338], + "nleqslant" => [0x02A7D, 0x00338], + "nles" => [0x02A7D, 0x00338], + "nless" => [0x0226E], + "nlsim" => [0x02274], + "nlt" => [0x0226E], + "nltri" => [0x022EA], + "nltrie" => [0x022EC], + "nmid" => [0x02224], + "nopf" => [0x1D55F], + "not" => [0x000AC], + "notin" => [0x02209], + "notinE" => [0x022F9, 0x00338], + "notindot" => [0x022F5, 0x00338], + "notinva" => [0x02209], + "notinvb" => [0x022F7], + "notinvc" => [0x022F6], + "notni" => [0x0220C], + "notniva" => [0x0220C], + "notnivb" => [0x022FE], + "notnivc" => [0x022FD], + "npar" => [0x02226], + "nparallel" => [0x02226], + "nparsl" => [0x02AFD, 0x020E5], + "npart" => [0x02202, 0x00338], + "npolint" => [0x02A14], + "npr" => [0x02280], + "nprcue" => [0x022E0], + "npre" => [0x02AAF, 0x00338], + "nprec" => [0x02280], + "npreceq" => [0x02AAF, 0x00338], + "nrArr" => [0x021CF], + "nrarr" => [0x0219B], + "nrarrc" => [0x02933, 0x00338], + "nrarrw" => [0x0219D, 0x00338], + "nrightarrow" => [0x0219B], + "nrtri" => [0x022EB], + "nrtrie" => [0x022ED], + "nsc" => [0x02281], + "nsccue" => [0x022E1], + "nsce" => [0x02AB0, 0x00338], + "nscr" => [0x1D4C3], + "nshortmid" => [0x02224], + "nshortparallel" => [0x02226], + "nsim" => [0x02241], + "nsime" => [0x02244], + "nsimeq" => [0x02244], + "nsmid" => [0x02224], + "nspar" => [0x02226], + "nsqsube" => [0x022E2], + "nsqsupe" => [0x022E3], + "nsub" => [0x02284], + "nsubE" => [0x02AC5, 0x00338], + "nsube" => [0x02288], + "nsubset" => [0x02282, 0x020D2], + "nsubseteq" => [0x02288], + "nsubseteqq" => [0x02AC5, 0x00338], + "nsucc" => [0x02281], + "nsucceq" => [0x02AB0, 0x00338], + "nsup" => [0x02285], + "nsupE" => [0x02AC6, 0x00338], + "nsupe" => [0x02289], + "nsupset" => [0x02283, 0x020D2], + "nsupseteq" => [0x02289], + "nsupseteqq" => [0x02AC6, 0x00338], + "ntgl" => [0x02279], + "ntilde" => [0x000F1], + "ntlg" => [0x02278], + "ntriangleleft" => [0x022EA], + "ntrianglelefteq" => [0x022EC], + "ntriangleright" => [0x022EB], + "ntrianglerighteq" => [0x022ED], + "nu" => [0x003BD], + "num" => [0x00023], + "numero" => [0x02116], + "numsp" => [0x02007], + "nvDash" => [0x022AD], + "nvHarr" => [0x02904], + "nvap" => [0x0224D, 0x020D2], + "nvdash" => [0x022AC], + "nvge" => [0x02265, 0x020D2], + "nvgt" => [0x0003E, 0x020D2], + "nvinfin" => [0x029DE], + "nvlArr" => [0x02902], + "nvle" => [0x02264, 0x020D2], + "nvlt" => [0x0003C, 0x020D2], + "nvltrie" => [0x022B4, 0x020D2], + "nvrArr" => [0x02903], + "nvrtrie" => [0x022B5, 0x020D2], + "nvsim" => [0x0223C, 0x020D2], + "nwArr" => [0x021D6], + "nwarhk" => [0x02923], + "nwarr" => [0x02196], + "nwarrow" => [0x02196], + "nwnear" => [0x02927], + "oS" => [0x024C8], + "oacute" => [0x000F3], + "oast" => [0x0229B], + "ocir" => [0x0229A], + "ocirc" => [0x000F4], + "ocy" => [0x0043E], + "odash" => [0x0229D], + "odblac" => [0x00151], + "odiv" => [0x02A38], + "odot" => [0x02299], + "odsold" => [0x029BC], + "oelig" => [0x00153], + "ofcir" => [0x029BF], + "ofr" => [0x1D52C], + "ogon" => [0x002DB], + "ograve" => [0x000F2], + "ogt" => [0x029C1], + "ohbar" => [0x029B5], + "ohm" => [0x003A9], + "oint" => [0x0222E], + "olarr" => [0x021BA], + "olcir" => [0x029BE], + "olcross" => [0x029BB], + "oline" => [0x0203E], + "olt" => [0x029C0], + "omacr" => [0x0014D], + "omega" => [0x003C9], + "omicron" => [0x003BF], + "omid" => [0x029B6], + "ominus" => [0x02296], + "oopf" => [0x1D560], + "opar" => [0x029B7], + "operp" => [0x029B9], + "oplus" => [0x02295], + "or" => [0x02228], + "orarr" => [0x021BB], + "ord" => [0x02A5D], + "order" => [0x02134], + "orderof" => [0x02134], + "ordf" => [0x000AA], + "ordm" => [0x000BA], + "origof" => [0x022B6], + "oror" => [0x02A56], + "orslope" => [0x02A57], + "orv" => [0x02A5B], + "oscr" => [0x02134], + "oslash" => [0x000F8], + "osol" => [0x02298], + "otilde" => [0x000F5], + "otimes" => [0x02297], + "otimesas" => [0x02A36], + "ouml" => [0x000F6], + "ovbar" => [0x0233D], + "par" => [0x02225], + "para" => [0x000B6], + "parallel" => [0x02225], + "parsim" => [0x02AF3], + "parsl" => [0x02AFD], + "part" => [0x02202], + "pcy" => [0x0043F], + "percnt" => [0x00025], + "period" => [0x0002E], + "permil" => [0x02030], + "perp" => [0x022A5], + "pertenk" => [0x02031], + "pfr" => [0x1D52D], + "phi" => [0x003C6], + "phiv" => [0x003D5], + "phmmat" => [0x02133], + "phone" => [0x0260E], + "pi" => [0x003C0], + "pitchfork" => [0x022D4], + "piv" => [0x003D6], + "planck" => [0x0210F], + "planckh" => [0x0210E], + "plankv" => [0x0210F], + "plus" => [0x0002B], + "plusacir" => [0x02A23], + "plusb" => [0x0229E], + "pluscir" => [0x02A22], + "plusdo" => [0x02214], + "plusdu" => [0x02A25], + "pluse" => [0x02A72], + "plusmn" => [0x000B1], + "plussim" => [0x02A26], + "plustwo" => [0x02A27], + "pm" => [0x000B1], + "pointint" => [0x02A15], + "popf" => [0x1D561], + "pound" => [0x000A3], + "pr" => [0x0227A], + "prE" => [0x02AB3], + "prap" => [0x02AB7], + "prcue" => [0x0227C], + "pre" => [0x02AAF], + "prec" => [0x0227A], + "precapprox" => [0x02AB7], + "preccurlyeq" => [0x0227C], + "preceq" => [0x02AAF], + "precnapprox" => [0x02AB9], + "precneqq" => [0x02AB5], + "precnsim" => [0x022E8], + "precsim" => [0x0227E], + "prime" => [0x02032], + "primes" => [0x02119], + "prnE" => [0x02AB5], + "prnap" => [0x02AB9], + "prnsim" => [0x022E8], + "prod" => [0x0220F], + "profalar" => [0x0232E], + "profline" => [0x02312], + "profsurf" => [0x02313], + "prop" => [0x0221D], + "propto" => [0x0221D], + "prsim" => [0x0227E], + "prurel" => [0x022B0], + "pscr" => [0x1D4C5], + "psi" => [0x003C8], + "puncsp" => [0x02008], + "qfr" => [0x1D52E], + "qint" => [0x02A0C], + "qopf" => [0x1D562], + "qprime" => [0x02057], + "qscr" => [0x1D4C6], + "quaternions" => [0x0210D], + "quatint" => [0x02A16], + "quest" => [0x0003F], + "questeq" => [0x0225F], + "quot" => [0x00022], + "rAarr" => [0x021DB], + "rArr" => [0x021D2], + "rAtail" => [0x0291C], + "rBarr" => [0x0290F], + "rHar" => [0x02964], + "race" => [0x0223D, 0x00331], + "racute" => [0x00155], + "radic" => [0x0221A], + "raemptyv" => [0x029B3], + "rang" => [0x027E9], + "rangd" => [0x02992], + "range" => [0x029A5], + "rangle" => [0x027E9], + "raquo" => [0x000BB], + "rarr" => [0x02192], + "rarrap" => [0x02975], + "rarrb" => [0x021E5], + "rarrbfs" => [0x02920], + "rarrc" => [0x02933], + "rarrfs" => [0x0291E], + "rarrhk" => [0x021AA], + "rarrlp" => [0x021AC], + "rarrpl" => [0x02945], + "rarrsim" => [0x02974], + "rarrtl" => [0x021A3], + "rarrw" => [0x0219D], + "ratail" => [0x0291A], + "ratio" => [0x02236], + "rationals" => [0x0211A], + "rbarr" => [0x0290D], + "rbbrk" => [0x02773], + "rbrace" => [0x0007D], + "rbrack" => [0x0005D], + "rbrke" => [0x0298C], + "rbrksld" => [0x0298E], + "rbrkslu" => [0x02990], + "rcaron" => [0x00159], + "rcedil" => [0x00157], + "rceil" => [0x02309], + "rcub" => [0x0007D], + "rcy" => [0x00440], + "rdca" => [0x02937], + "rdldhar" => [0x02969], + "rdquo" => [0x0201D], + "rdquor" => [0x0201D], + "rdsh" => [0x021B3], + "real" => [0x0211C], + "realine" => [0x0211B], + "realpart" => [0x0211C], + "reals" => [0x0211D], + "rect" => [0x025AD], + "reg" => [0x000AE], + "rfisht" => [0x0297D], + "rfloor" => [0x0230B], + "rfr" => [0x1D52F], + "rhard" => [0x021C1], + "rharu" => [0x021C0], + "rharul" => [0x0296C], + "rho" => [0x003C1], + "rhov" => [0x003F1], + "rightarrow" => [0x02192], + "rightarrowtail" => [0x021A3], + "rightharpoondown" => [0x021C1], + "rightharpoonup" => [0x021C0], + "rightleftarrows" => [0x021C4], + "rightleftharpoons" => [0x021CC], + "rightrightarrows" => [0x021C9], + "rightsquigarrow" => [0x0219D], + "rightthreetimes" => [0x022CC], + "ring" => [0x002DA], + "risingdotseq" => [0x02253], + "rlarr" => [0x021C4], + "rlhar" => [0x021CC], + "rlm" => [0x0200F], + "rmoust" => [0x023B1], + "rmoustache" => [0x023B1], + "rnmid" => [0x02AEE], + "roang" => [0x027ED], + "roarr" => [0x021FE], + "robrk" => [0x027E7], + "ropar" => [0x02986], + "ropf" => [0x1D563], + "roplus" => [0x02A2E], + "rotimes" => [0x02A35], + "rpar" => [0x00029], + "rpargt" => [0x02994], + "rppolint" => [0x02A12], + "rrarr" => [0x021C9], + "rsaquo" => [0x0203A], + "rscr" => [0x1D4C7], + "rsh" => [0x021B1], + "rsqb" => [0x0005D], + "rsquo" => [0x02019], + "rsquor" => [0x02019], + "rthree" => [0x022CC], + "rtimes" => [0x022CA], + "rtri" => [0x025B9], + "rtrie" => [0x022B5], + "rtrif" => [0x025B8], + "rtriltri" => [0x029CE], + "ruluhar" => [0x02968], + "rx" => [0x0211E], + "sacute" => [0x0015B], + "sbquo" => [0x0201A], + "sc" => [0x0227B], + "scE" => [0x02AB4], + "scap" => [0x02AB8], + "scaron" => [0x00161], + "sccue" => [0x0227D], + "sce" => [0x02AB0], + "scedil" => [0x0015F], + "scirc" => [0x0015D], + "scnE" => [0x02AB6], + "scnap" => [0x02ABA], + "scnsim" => [0x022E9], + "scpolint" => [0x02A13], + "scsim" => [0x0227F], + "scy" => [0x00441], + "sdot" => [0x022C5], + "sdotb" => [0x022A1], + "sdote" => [0x02A66], + "seArr" => [0x021D8], + "searhk" => [0x02925], + "searr" => [0x02198], + "searrow" => [0x02198], + "sect" => [0x000A7], + "semi" => [0x0003B], + "seswar" => [0x02929], + "setminus" => [0x02216], + "setmn" => [0x02216], + "sext" => [0x02736], + "sfr" => [0x1D530], + "sfrown" => [0x02322], + "sharp" => [0x0266F], + "shchcy" => [0x00449], + "shcy" => [0x00448], + "shortmid" => [0x02223], + "shortparallel" => [0x02225], + "shy" => [0x000AD], + "sigma" => [0x003C3], + "sigmaf" => [0x003C2], + "sigmav" => [0x003C2], + "sim" => [0x0223C], + "simdot" => [0x02A6A], + "sime" => [0x02243], + "simeq" => [0x02243], + "simg" => [0x02A9E], + "simgE" => [0x02AA0], + "siml" => [0x02A9D], + "simlE" => [0x02A9F], + "simne" => [0x02246], + "simplus" => [0x02A24], + "simrarr" => [0x02972], + "slarr" => [0x02190], + "smallsetminus" => [0x02216], + "smashp" => [0x02A33], + "smeparsl" => [0x029E4], + "smid" => [0x02223], + "smile" => [0x02323], + "smt" => [0x02AAA], + "smte" => [0x02AAC], + "smtes" => [0x02AAC, 0x0FE00], + "softcy" => [0x0044C], + "sol" => [0x0002F], + "solb" => [0x029C4], + "solbar" => [0x0233F], + "sopf" => [0x1D564], + "spades" => [0x02660], + "spadesuit" => [0x02660], + "spar" => [0x02225], + "sqcap" => [0x02293], + "sqcaps" => [0x02293, 0x0FE00], + "sqcup" => [0x02294], + "sqcups" => [0x02294, 0x0FE00], + "sqsub" => [0x0228F], + "sqsube" => [0x02291], + "sqsubset" => [0x0228F], + "sqsubseteq" => [0x02291], + "sqsup" => [0x02290], + "sqsupe" => [0x02292], + "sqsupset" => [0x02290], + "sqsupseteq" => [0x02292], + "squ" => [0x025A1], + "square" => [0x025A1], + "squarf" => [0x025AA], + "squf" => [0x025AA], + "srarr" => [0x02192], + "sscr" => [0x1D4C8], + "ssetmn" => [0x02216], + "ssmile" => [0x02323], + "sstarf" => [0x022C6], + "star" => [0x02606], + "starf" => [0x02605], + "straightepsilon" => [0x003F5], + "straightphi" => [0x003D5], + "strns" => [0x000AF], + "sub" => [0x02282], + "subE" => [0x02AC5], + "subdot" => [0x02ABD], + "sube" => [0x02286], + "subedot" => [0x02AC3], + "submult" => [0x02AC1], + "subnE" => [0x02ACB], + "subne" => [0x0228A], + "subplus" => [0x02ABF], + "subrarr" => [0x02979], + "subset" => [0x02282], + "subseteq" => [0x02286], + "subseteqq" => [0x02AC5], + "subsetneq" => [0x0228A], + "subsetneqq" => [0x02ACB], + "subsim" => [0x02AC7], + "subsub" => [0x02AD5], + "subsup" => [0x02AD3], + "succ" => [0x0227B], + "succapprox" => [0x02AB8], + "succcurlyeq" => [0x0227D], + "succeq" => [0x02AB0], + "succnapprox" => [0x02ABA], + "succneqq" => [0x02AB6], + "succnsim" => [0x022E9], + "succsim" => [0x0227F], + "sum" => [0x02211], + "sung" => [0x0266A], + "sup" => [0x02283], + "sup1" => [0x000B9], + "sup2" => [0x000B2], + "sup3" => [0x000B3], + "supE" => [0x02AC6], + "supdot" => [0x02ABE], + "supdsub" => [0x02AD8], + "supe" => [0x02287], + "supedot" => [0x02AC4], + "suphsol" => [0x027C9], + "suphsub" => [0x02AD7], + "suplarr" => [0x0297B], + "supmult" => [0x02AC2], + "supnE" => [0x02ACC], + "supne" => [0x0228B], + "supplus" => [0x02AC0], + "supset" => [0x02283], + "supseteq" => [0x02287], + "supseteqq" => [0x02AC6], + "supsetneq" => [0x0228B], + "supsetneqq" => [0x02ACC], + "supsim" => [0x02AC8], + "supsub" => [0x02AD4], + "supsup" => [0x02AD6], + "swArr" => [0x021D9], + "swarhk" => [0x02926], + "swarr" => [0x02199], + "swarrow" => [0x02199], + "swnwar" => [0x0292A], + "szlig" => [0x000DF], + "target" => [0x02316], + "tau" => [0x003C4], + "tbrk" => [0x023B4], + "tcaron" => [0x00165], + "tcedil" => [0x00163], + "tcy" => [0x00442], + "tdot" => [0x020DB], + "telrec" => [0x02315], + "tfr" => [0x1D531], + "there4" => [0x02234], + "therefore" => [0x02234], + "theta" => [0x003B8], + "thetasym" => [0x003D1], + "thetav" => [0x003D1], + "thickapprox" => [0x02248], + "thicksim" => [0x0223C], + "thinsp" => [0x02009], + "thkap" => [0x02248], + "thksim" => [0x0223C], + "thorn" => [0x000FE], + "tilde" => [0x002DC], + "times" => [0x000D7], + "timesb" => [0x022A0], + "timesbar" => [0x02A31], + "timesd" => [0x02A30], + "tint" => [0x0222D], + "toea" => [0x02928], + "top" => [0x022A4], + "topbot" => [0x02336], + "topcir" => [0x02AF1], + "topf" => [0x1D565], + "topfork" => [0x02ADA], + "tosa" => [0x02929], + "tprime" => [0x02034], + "trade" => [0x02122], + "triangle" => [0x025B5], + "triangledown" => [0x025BF], + "triangleleft" => [0x025C3], + "trianglelefteq" => [0x022B4], + "triangleq" => [0x0225C], + "triangleright" => [0x025B9], + "trianglerighteq" => [0x022B5], + "tridot" => [0x025EC], + "trie" => [0x0225C], + "triminus" => [0x02A3A], + "triplus" => [0x02A39], + "trisb" => [0x029CD], + "tritime" => [0x02A3B], + "trpezium" => [0x023E2], + "tscr" => [0x1D4C9], + "tscy" => [0x00446], + "tshcy" => [0x0045B], + "tstrok" => [0x00167], + "twixt" => [0x0226C], + "twoheadleftarrow" => [0x0219E], + "twoheadrightarrow" => [0x021A0], + "uArr" => [0x021D1], + "uHar" => [0x02963], + "uacute" => [0x000FA], + "uarr" => [0x02191], + "ubrcy" => [0x0045E], + "ubreve" => [0x0016D], + "ucirc" => [0x000FB], + "ucy" => [0x00443], + "udarr" => [0x021C5], + "udblac" => [0x00171], + "udhar" => [0x0296E], + "ufisht" => [0x0297E], + "ufr" => [0x1D532], + "ugrave" => [0x000F9], + "uharl" => [0x021BF], + "uharr" => [0x021BE], + "uhblk" => [0x02580], + "ulcorn" => [0x0231C], + "ulcorner" => [0x0231C], + "ulcrop" => [0x0230F], + "ultri" => [0x025F8], + "umacr" => [0x0016B], + "uml" => [0x000A8], + "uogon" => [0x00173], + "uopf" => [0x1D566], + "uparrow" => [0x02191], + "updownarrow" => [0x02195], + "upharpoonleft" => [0x021BF], + "upharpoonright" => [0x021BE], + "uplus" => [0x0228E], + "upsi" => [0x003C5], + "upsih" => [0x003D2], + "upsilon" => [0x003C5], + "upuparrows" => [0x021C8], + "urcorn" => [0x0231D], + "urcorner" => [0x0231D], + "urcrop" => [0x0230E], + "uring" => [0x0016F], + "urtri" => [0x025F9], + "uscr" => [0x1D4CA], + "utdot" => [0x022F0], + "utilde" => [0x00169], + "utri" => [0x025B5], + "utrif" => [0x025B4], + "uuarr" => [0x021C8], + "uuml" => [0x000FC], + "uwangle" => [0x029A7], + "vArr" => [0x021D5], + "vBar" => [0x02AE8], + "vBarv" => [0x02AE9], + "vDash" => [0x022A8], + "vangrt" => [0x0299C], + "varepsilon" => [0x003F5], + "varkappa" => [0x003F0], + "varnothing" => [0x02205], + "varphi" => [0x003D5], + "varpi" => [0x003D6], + "varpropto" => [0x0221D], + "varr" => [0x02195], + "varrho" => [0x003F1], + "varsigma" => [0x003C2], + "varsubsetneq" => [0x0228A, 0x0FE00], + "varsubsetneqq" => [0x02ACB, 0x0FE00], + "varsupsetneq" => [0x0228B, 0x0FE00], + "varsupsetneqq" => [0x02ACC, 0x0FE00], + "vartheta" => [0x003D1], + "vartriangleleft" => [0x022B2], + "vartriangleright" => [0x022B3], + "vcy" => [0x00432], + "vdash" => [0x022A2], + "vee" => [0x02228], + "veebar" => [0x022BB], + "veeeq" => [0x0225A], + "vellip" => [0x022EE], + "verbar" => [0x0007C], + "vert" => [0x0007C], + "vfr" => [0x1D533], + "vltri" => [0x022B2], + "vnsub" => [0x02282, 0x020D2], + "vnsup" => [0x02283, 0x020D2], + "vopf" => [0x1D567], + "vprop" => [0x0221D], + "vrtri" => [0x022B3], + "vscr" => [0x1D4CB], + "vsubnE" => [0x02ACB, 0x0FE00], + "vsubne" => [0x0228A, 0x0FE00], + "vsupnE" => [0x02ACC, 0x0FE00], + "vsupne" => [0x0228B, 0x0FE00], + "vzigzag" => [0x0299A], + "wcirc" => [0x00175], + "wedbar" => [0x02A5F], + "wedge" => [0x02227], + "wedgeq" => [0x02259], + "weierp" => [0x02118], + "wfr" => [0x1D534], + "wopf" => [0x1D568], + "wp" => [0x02118], + "wr" => [0x02240], + "wreath" => [0x02240], + "wscr" => [0x1D4CC], + "xcap" => [0x022C2], + "xcirc" => [0x025EF], + "xcup" => [0x022C3], + "xdtri" => [0x025BD], + "xfr" => [0x1D535], + "xhArr" => [0x027FA], + "xharr" => [0x027F7], + "xi" => [0x003BE], + "xlArr" => [0x027F8], + "xlarr" => [0x027F5], + "xmap" => [0x027FC], + "xnis" => [0x022FB], + "xodot" => [0x02A00], + "xopf" => [0x1D569], + "xoplus" => [0x02A01], + "xotime" => [0x02A02], + "xrArr" => [0x027F9], + "xrarr" => [0x027F6], + "xscr" => [0x1D4CD], + "xsqcup" => [0x02A06], + "xuplus" => [0x02A04], + "xutri" => [0x025B3], + "xvee" => [0x022C1], + "xwedge" => [0x022C0], + "yacute" => [0x000FD], + "yacy" => [0x0044F], + "ycirc" => [0x00177], + "ycy" => [0x0044B], + "yen" => [0x000A5], + "yfr" => [0x1D536], + "yicy" => [0x00457], + "yopf" => [0x1D56A], + "yscr" => [0x1D4CE], + "yucy" => [0x0044E], + "yuml" => [0x000FF], + "zacute" => [0x0017A], + "zcaron" => [0x0017E], + "zcy" => [0x00437], + "zdot" => [0x0017C], + "zeetrf" => [0x02128], + "zeta" => [0x003B6], + "zfr" => [0x1D537], + "zhcy" => [0x00436], + "zigrarr" => [0x021DD], + "zopf" => [0x1D56B], + "zscr" => [0x1D4CF], + "zwj" => [0x0200D], + "zwnj" => [0x0200C], +} + diff --git a/jni/ruby/lib/rdoc/markdown/literals_1_9.rb b/jni/ruby/lib/rdoc/markdown/literals_1_9.rb new file mode 100644 index 0000000..f7bfbe2 --- /dev/null +++ b/jni/ruby/lib/rdoc/markdown/literals_1_9.rb @@ -0,0 +1,420 @@ +# coding: UTF-8 +# :markup: markdown + +## +#-- +# This set of literals is for Ruby 1.9 regular expressions and gives full +# unicode support. +# +# Unlike peg-markdown, this set of literals recognizes Unicode alphanumeric +# characters, newlines and spaces. +class RDoc::Markdown::Literals + # :stopdoc: + + # This is distinct from setup_parser so that a standalone parser + # can redefine #initialize and still have access to the proper + # parser setup code. + def initialize(str, debug=false) + setup_parser(str, debug) + end + + + + # Prepares for parsing +str+. If you define a custom initialize you must + # call this method before #parse + def setup_parser(str, debug=false) + set_string str, 0 + @memoizations = Hash.new { |h,k| h[k] = {} } + @result = nil + @failed_rule = nil + @failing_rule_offset = -1 + + setup_foreign_grammar + end + + attr_reader :string + attr_reader :failing_rule_offset + attr_accessor :result, :pos + + def current_column(target=pos) + if c = string.rindex("\n", target-1) + return target - c - 1 + end + + target + 1 + end + + def current_line(target=pos) + cur_offset = 0 + cur_line = 0 + + string.each_line do |line| + cur_line += 1 + cur_offset += line.size + return cur_line if cur_offset >= target + end + + -1 + end + + def lines + lines = [] + string.each_line { |l| lines << l } + lines + end + + + + def get_text(start) + @string[start..@pos-1] + end + + # Sets the string and current parsing position for the parser. + def set_string string, pos + @string = string + @string_size = string ? string.size : 0 + @pos = pos + end + + def show_pos + width = 10 + if @pos < width + "#{@pos} (\"#{@string[0,@pos]}\" @ \"#{@string[@pos,width]}\")" + else + "#{@pos} (\"... #{@string[@pos - width, width]}\" @ \"#{@string[@pos,width]}\")" + end + end + + def failure_info + l = current_line @failing_rule_offset + c = current_column @failing_rule_offset + + if @failed_rule.kind_of? Symbol + info = self.class::Rules[@failed_rule] + "line #{l}, column #{c}: failed rule '#{info.name}' = '#{info.rendered}'" + else + "line #{l}, column #{c}: failed rule '#{@failed_rule}'" + end + end + + def failure_caret + l = current_line @failing_rule_offset + c = current_column @failing_rule_offset + + line = lines[l-1] + "#{line}\n#{' ' * (c - 1)}^" + end + + def failure_character + l = current_line @failing_rule_offset + c = current_column @failing_rule_offset + lines[l-1][c-1, 1] + end + + def failure_oneline + l = current_line @failing_rule_offset + c = current_column @failing_rule_offset + + char = lines[l-1][c-1, 1] + + if @failed_rule.kind_of? Symbol + info = self.class::Rules[@failed_rule] + "@#{l}:#{c} failed rule '#{info.name}', got '#{char}'" + else + "@#{l}:#{c} failed rule '#{@failed_rule}', got '#{char}'" + end + end + + class ParseError < RuntimeError + end + + def raise_error + raise ParseError, failure_oneline + end + + def show_error(io=STDOUT) + error_pos = @failing_rule_offset + line_no = current_line(error_pos) + col_no = current_column(error_pos) + + io.puts "On line #{line_no}, column #{col_no}:" + + if @failed_rule.kind_of? Symbol + info = self.class::Rules[@failed_rule] + io.puts "Failed to match '#{info.rendered}' (rule '#{info.name}')" + else + io.puts "Failed to match rule '#{@failed_rule}'" + end + + io.puts "Got: #{string[error_pos,1].inspect}" + line = lines[line_no-1] + io.puts "=> #{line}" + io.print(" " * (col_no + 3)) + io.puts "^" + end + + def set_failed_rule(name) + if @pos > @failing_rule_offset + @failed_rule = name + @failing_rule_offset = @pos + end + end + + attr_reader :failed_rule + + def match_string(str) + len = str.size + if @string[pos,len] == str + @pos += len + return str + end + + return nil + end + + def scan(reg) + if m = reg.match(@string[@pos..-1]) + width = m.end(0) + @pos += width + return true + end + + return nil + end + + if "".respond_to? :ord + def get_byte + if @pos >= @string_size + return nil + end + + s = @string[@pos].ord + @pos += 1 + s + end + else + def get_byte + if @pos >= @string_size + return nil + end + + s = @string[@pos] + @pos += 1 + s + end + end + + def parse(rule=nil) + # We invoke the rules indirectly via apply + # instead of by just calling them as methods because + # if the rules use left recursion, apply needs to + # manage that. + + if !rule + apply(:_root) + else + method = rule.gsub("-","_hyphen_") + apply :"_#{method}" + end + end + + class MemoEntry + def initialize(ans, pos) + @ans = ans + @pos = pos + @result = nil + @set = false + @left_rec = false + end + + attr_reader :ans, :pos, :result, :set + attr_accessor :left_rec + + def move!(ans, pos, result) + @ans = ans + @pos = pos + @result = result + @set = true + @left_rec = false + end + end + + def external_invoke(other, rule, *args) + old_pos = @pos + old_string = @string + + set_string other.string, other.pos + + begin + if val = __send__(rule, *args) + other.pos = @pos + other.result = @result + else + other.set_failed_rule "#{self.class}##{rule}" + end + val + ensure + set_string old_string, old_pos + end + end + + def apply_with_args(rule, *args) + memo_key = [rule, args] + if m = @memoizations[memo_key][@pos] + @pos = m.pos + if !m.set + m.left_rec = true + return nil + end + + @result = m.result + + return m.ans + else + m = MemoEntry.new(nil, @pos) + @memoizations[memo_key][@pos] = m + start_pos = @pos + + ans = __send__ rule, *args + + lr = m.left_rec + + m.move! ans, @pos, @result + + # Don't bother trying to grow the left recursion + # if it's failing straight away (thus there is no seed) + if ans and lr + return grow_lr(rule, args, start_pos, m) + else + return ans + end + + return ans + end + end + + def apply(rule) + if m = @memoizations[rule][@pos] + @pos = m.pos + if !m.set + m.left_rec = true + return nil + end + + @result = m.result + + return m.ans + else + m = MemoEntry.new(nil, @pos) + @memoizations[rule][@pos] = m + start_pos = @pos + + ans = __send__ rule + + lr = m.left_rec + + m.move! ans, @pos, @result + + # Don't bother trying to grow the left recursion + # if it's failing straight away (thus there is no seed) + if ans and lr + return grow_lr(rule, nil, start_pos, m) + else + return ans + end + + return ans + end + end + + def grow_lr(rule, args, start_pos, m) + while true + @pos = start_pos + @result = m.result + + if args + ans = __send__ rule, *args + else + ans = __send__ rule + end + return nil unless ans + + break if @pos <= m.pos + + m.move! ans, @pos, @result + end + + @result = m.result + @pos = m.pos + return m.ans + end + + class RuleInfo + def initialize(name, rendered) + @name = name + @rendered = rendered + end + + attr_reader :name, :rendered + end + + def self.rule_info(name, rendered) + RuleInfo.new(name, rendered) + end + + + # :startdoc: + # :stopdoc: + def setup_foreign_grammar; end + + # Alphanumeric = /\p{Word}/ + def _Alphanumeric + _tmp = scan(/\A(?-mix:\p{Word})/) + set_failed_rule :_Alphanumeric unless _tmp + return _tmp + end + + # AlphanumericAscii = /[A-Za-z0-9]/ + def _AlphanumericAscii + _tmp = scan(/\A(?-mix:[A-Za-z0-9])/) + set_failed_rule :_AlphanumericAscii unless _tmp + return _tmp + end + + # BOM = "uFEFF" + def _BOM + _tmp = match_string("uFEFF") + set_failed_rule :_BOM unless _tmp + return _tmp + end + + # Newline = /\n|\r\n?|\p{Zl}|\p{Zp}/ + def _Newline + _tmp = scan(/\A(?-mix:\n|\r\n?|\p{Zl}|\p{Zp})/) + set_failed_rule :_Newline unless _tmp + return _tmp + end + + # NonAlphanumeric = /\p{^Word}/ + def _NonAlphanumeric + _tmp = scan(/\A(?-mix:\p{^Word})/) + set_failed_rule :_NonAlphanumeric unless _tmp + return _tmp + end + + # Spacechar = /\t|\p{Zs}/ + def _Spacechar + _tmp = scan(/\A(?-mix:\t|\p{Zs})/) + set_failed_rule :_Spacechar unless _tmp + return _tmp + end + + Rules = {} + Rules[:_Alphanumeric] = rule_info("Alphanumeric", "/\\p{Word}/") + Rules[:_AlphanumericAscii] = rule_info("AlphanumericAscii", "/[A-Za-z0-9]/") + Rules[:_BOM] = rule_info("BOM", "\"uFEFF\"") + Rules[:_Newline] = rule_info("Newline", "/\\n|\\r\\n?|\\p{Zl}|\\p{Zp}/") + Rules[:_NonAlphanumeric] = rule_info("NonAlphanumeric", "/\\p{^Word}/") + Rules[:_Spacechar] = rule_info("Spacechar", "/\\t|\\p{Zs}/") + # :startdoc: +end diff --git a/jni/ruby/lib/rdoc/markup.rb b/jni/ruby/lib/rdoc/markup.rb new file mode 100644 index 0000000..0e754ff --- /dev/null +++ b/jni/ruby/lib/rdoc/markup.rb @@ -0,0 +1,869 @@ +## +# RDoc::Markup parses plain text documents and attempts to decompose them into +# their constituent parts. Some of these parts are high-level: paragraphs, +# chunks of verbatim text, list entries and the like. Other parts happen at +# the character level: a piece of bold text, a word in code font. This markup +# is similar in spirit to that used on WikiWiki webs, where folks create web +# pages using a simple set of formatting rules. +# +# RDoc::Markup and other markup formats do no output formatting, this is +# handled by the RDoc::Markup::Formatter subclasses. +# +# = Supported Formats +# +# Besides the RDoc::Markup format, the following formats are built in to RDoc: +# +# markdown:: +# The markdown format as described by +# http://daringfireball.net/projects/markdown/. See RDoc::Markdown for +# details on the parser and supported extensions. +# rd:: +# The rdtool format. See RDoc::RD for details on the parser and format. +# tomdoc:: +# The TomDoc format as described by http://tomdoc.org/. See RDoc::TomDoc +# for details on the parser and supported extensions. +# +# You can choose a markup format using the following methods: +# +# per project:: +# If you build your documentation with rake use RDoc::Task#markup. +# +# If you build your documentation by hand run: +# +# rdoc --markup your_favorite_format --write-options +# +# and commit <tt>.rdoc_options</tt> and ship it with your packaged gem. +# per file:: +# At the top of the file use the <tt>:markup:</tt> directive to set the +# default format for the rest of the file. +# per comment:: +# Use the <tt>:markup:</tt> directive at the top of a comment you want +# to write in a different format. +# +# = RDoc::Markup +# +# RDoc::Markup is extensible at runtime: you can add \new markup elements to +# be recognized in the documents that RDoc::Markup parses. +# +# RDoc::Markup is intended to be the basis for a family of tools which share +# the common requirement that simple, plain-text should be rendered in a +# variety of different output formats and media. It is envisaged that +# RDoc::Markup could be the basis for formatting RDoc style comment blocks, +# Wiki entries, and online FAQs. +# +# == Synopsis +# +# This code converts +input_string+ to HTML. The conversion takes place in +# the +convert+ method, so you can use the same RDoc::Markup converter to +# convert multiple input strings. +# +# require 'rdoc' +# +# h = RDoc::Markup::ToHtml.new(RDoc::Options.new) +# +# puts h.convert(input_string) +# +# You can extend the RDoc::Markup parser to recognize new markup +# sequences, and to add special processing for text that matches a +# regular expression. Here we make WikiWords significant to the parser, +# and also make the sequences {word} and \<no>text...</no> signify +# strike-through text. We then subclass the HTML output class to deal +# with these: +# +# require 'rdoc' +# +# class WikiHtml < RDoc::Markup::ToHtml +# def handle_special_WIKIWORD(special) +# "<font color=red>" + special.text + "</font>" +# end +# end +# +# markup = RDoc::Markup.new +# markup.add_word_pair("{", "}", :STRIKE) +# markup.add_html("no", :STRIKE) +# +# markup.add_special(/\b([A-Z][a-z]+[A-Z]\w+)/, :WIKIWORD) +# +# wh = WikiHtml.new RDoc::Options.new, markup +# wh.add_tag(:STRIKE, "<strike>", "</strike>") +# +# puts "<body>#{wh.convert ARGF.read}</body>" +# +# == Encoding +# +# Where Encoding support is available, RDoc will automatically convert all +# documents to the same output encoding. The output encoding can be set via +# RDoc::Options#encoding and defaults to Encoding.default_external. +# +# = \RDoc Markup Reference +# +# == Block Markup +# +# === Paragraphs and Verbatim +# +# The markup engine looks for a document's natural left margin. This is +# used as the initial margin for the document. +# +# Consecutive lines starting at this margin are considered to be a +# paragraph. Empty lines separate paragraphs. +# +# Any line that starts to the right of the current margin is treated +# as verbatim text. This is useful for code listings: +# +# 3.times { puts "Ruby" } +# +# In verbatim text, two or more blank lines are collapsed into one, +# and trailing blank lines are removed: +# +# This is the first line +# +# +# This is the second non-blank line, +# after 2 blank lines in the source markup. +# +# +# There were two trailing blank lines right above this paragraph, that +# have been removed. In addition, the verbatim text has been shifted +# left, so the amount of indentation of verbatim text is unimportant. +# +# For HTML output RDoc makes a small effort to determine if a verbatim section +# contains Ruby source code. If so, the verbatim block will be marked up as +# HTML. Triggers include "def", "class", "module", "require", the "hash +# rocket"# (=>) or a block call with a parameter. +# +# === Headers +# +# A line starting with an equal sign (=) is treated as a +# heading. Level one headings have one equals sign, level two headings +# have two, and so on until level six, which is the maximum +# (seven hyphens or more result in a level six heading). +# +# For example, the above header was obtained with: +# +# === Headers +# +# In HTML output headers have an id matching their name. The above example's +# HTML is: +# +# <h3 id="label-Headers">Headers</h3> +# +# If a heading is inside a method body the id will be prefixed with the +# method's id. If the above header where in the documentation for a method +# such as: +# +# ## +# # This method does fun things +# # +# # = Example +# # +# # Example of fun things goes here ... +# +# def do_fun_things +# end +# +# The header's id would be: +# +# <h1 id="method-i-do_fun_things-label-Example">Example</h1> +# +# The label can be linked-to using <tt>SomeClass@Headers</tt>. See +# {Links}[RDoc::Markup@Links] for further details. +# +# === Rules +# +# A line starting with three or more hyphens (at the current indent) +# generates a horizontal rule. +# +# --- +# +# produces: +# +# --- +# +# === Simple Lists +# +# If a paragraph starts with a "*", "-", "<digit>." or "<letter>.", +# then it is taken to be the start of a list. The margin is increased to be +# the first non-space following the list start flag. Subsequent lines +# should be indented to this new margin until the list ends. For example: +# +# * this is a list with three paragraphs in +# the first item. This is the first paragraph. +# +# And this is the second paragraph. +# +# 1. This is an indented, numbered list. +# 2. This is the second item in that list +# +# This is the third conventional paragraph in the +# first list item. +# +# * This is the second item in the original list +# +# produces: +# +# * this is a list with three paragraphs in +# the first item. This is the first paragraph. +# +# And this is the second paragraph. +# +# 1. This is an indented, numbered list. +# 2. This is the second item in that list +# +# This is the third conventional paragraph in the +# first list item. +# +# * This is the second item in the original list +# +# === Labeled Lists +# +# You can also construct labeled lists, sometimes called description +# or definition lists. Do this by putting the label in square brackets +# and indenting the list body: +# +# [cat] a small furry mammal +# that seems to sleep a lot +# +# [ant] a little insect that is known +# to enjoy picnics +# +# produces: +# +# [cat] a small furry mammal +# that seems to sleep a lot +# +# [ant] a little insect that is known +# to enjoy picnics +# +# If you want the list bodies to line up to the left of the labels, +# use two colons: +# +# cat:: a small furry mammal +# that seems to sleep a lot +# +# ant:: a little insect that is known +# to enjoy picnics +# +# produces: +# +# cat:: a small furry mammal +# that seems to sleep a lot +# +# ant:: a little insect that is known +# to enjoy picnics +# +# Notice that blank lines right after the label are ignored in labeled lists: +# +# [one] +# +# definition 1 +# +# [two] +# +# definition 2 +# +# produces the same output as +# +# [one] definition 1 +# [two] definition 2 +# +# +# === Lists and Verbatim +# +# If you want to introduce a verbatim section right after a list, it has to be +# less indented than the list item bodies, but more indented than the list +# label, letter, digit or bullet. For instance: +# +# * point 1 +# +# * point 2, first paragraph +# +# point 2, second paragraph +# verbatim text inside point 2 +# point 2, third paragraph +# verbatim text outside of the list (the list is therefore closed) +# regular paragraph after the list +# +# produces: +# +# * point 1 +# +# * point 2, first paragraph +# +# point 2, second paragraph +# verbatim text inside point 2 +# point 2, third paragraph +# verbatim text outside of the list (the list is therefore closed) +# regular paragraph after the list +# +# == Text Markup +# +# === Bold, Italic, Typewriter Text +# +# You can use markup within text (except verbatim) to change the +# appearance of parts of that text. Out of the box, RDoc::Markup +# supports word-based and general markup. +# +# Word-based markup uses flag characters around individual words: +# +# <tt>\*_word_\*</tt>:: displays _word_ in a *bold* font +# <tt>\__word_\_</tt>:: displays _word_ in an _emphasized_ font +# <tt>\+_word_\+</tt>:: displays _word_ in a +code+ font +# +# General markup affects text between a start delimiter and an end +# delimiter. Not surprisingly, these delimiters look like HTML markup. +# +# <tt>\<b>_text_</b></tt>:: displays _text_ in a *bold* font +# <tt>\<em>_text_</em></tt>:: displays _text_ in an _emphasized_ font +# (alternate tag: <tt>\<i></tt>) +# <tt>\<tt>_text_\</tt></tt>:: displays _text_ in a +code+ font +# (alternate tag: <tt>\<code></tt>) +# +# Unlike conventional Wiki markup, general markup can cross line +# boundaries. You can turn off the interpretation of markup by +# preceding the first character with a backslash (see <i>Escaping +# Text Markup</i>, below). +# +# === Links +# +# Links to starting with +http:+, +https:+, +mailto:+, +ftp:+ or +www.+ +# are recognized. An HTTP url that references an external image is converted +# into an inline image element. +# +# Classes and methods will be automatically linked to their definition. For +# example, <tt>RDoc::Markup</tt> will link to this documentation. By default +# methods will only be automatically linked if they contain an <tt>_</tt> (all +# methods can be automatically linked through the <tt>--hyperlink-all</tt> +# command line option). +# +# Single-word methods can be linked by using the <tt>#</tt> character for +# instance methods or <tt>::</tt> for class methods. For example, +# <tt>#convert</tt> links to #convert. A class or method may be combined like +# <tt>RDoc::Markup#convert</tt>. +# +# A heading inside the documentation can be linked by following the class +# or method by an <tt>@</tt> then the heading name. +# <tt>RDoc::Markup@Links</tt> will link to this section like this: +# RDoc::Markup@Links. Spaces in headings with multiple words must be escaped +# with <tt>+</tt> like <tt>RDoc::Markup@Escaping+Text+Markup</tt>. +# Punctuation and other special characters must be escaped like CGI.escape. +# +# The <tt>@</tt> can also be used to link to sections. If a section and a +# heading share the same name the section is preferred for the link. +# +# Links can also be of the form <tt>label[url]</tt>, in which case +label+ is +# used in the displayed text, and +url+ is used as the target. If +label+ +# contains multiple words, put it in braces: <tt>{multi word label}[url]</tt>. +# The +url+ may be an +http:+-type link or a cross-reference to a class, +# module or method with a label. +# +# Links with the <code>rdoc-image:</code> scheme will create an image tag for +# HTML output. Only fully-qualified URLs are supported. +# +# Links with the <tt>rdoc-ref:</tt> scheme will link to the referenced class, +# module, method, file, etc. If the referenced item is does not exist +# no link will be generated and <tt>rdoc-ref:</tt> will be removed from the +# resulting text. +# +# Links starting with <tt>rdoc-label:label_name</tt> will link to the +# +label_name+. You can create a label for the current link (for +# bidirectional links) by supplying a name for the current link like +# <tt>rdoc-label:label-other:label-mine</tt>. +# +# Links starting with +link:+ refer to local files whose path is relative to +# the <tt>--op</tt> directory. Use <tt>rdoc-ref:</tt> instead of +# <tt>link:</tt> to link to files generated by RDoc as the link target may +# be different across RDoc generators. +# +# Example links: +# +# https://github.com/rdoc/rdoc +# mailto:user@example.com +# {RDoc Documentation}[http://rdoc.rubyforge.org] +# {RDoc Markup}[rdoc-ref:RDoc::Markup] +# +# === Escaping Text Markup +# +# Text markup can be escaped with a backslash, as in \<tt>, which was obtained +# with <tt>\\<tt></tt>. Except in verbatim sections and between \<tt> tags, +# to produce a backslash you have to double it unless it is followed by a +# space, tab or newline. Otherwise, the HTML formatter will discard it, as it +# is used to escape potential links: +# +# * The \ must be doubled if not followed by white space: \\. +# * But not in \<tt> tags: in a Regexp, <tt>\S</tt> matches non-space. +# * This is a link to {ruby-lang}[www.ruby-lang.org]. +# * This is not a link, however: \{ruby-lang.org}[www.ruby-lang.org]. +# * This will not be linked to \RDoc::RDoc#document +# +# generates: +# +# * The \ must be doubled if not followed by white space: \\. +# * But not in \<tt> tags: in a Regexp, <tt>\S</tt> matches non-space. +# * This is a link to {ruby-lang}[www.ruby-lang.org] +# * This is not a link, however: \{ruby-lang.org}[www.ruby-lang.org] +# * This will not be linked to \RDoc::RDoc#document +# +# Inside \<tt> tags, more precisely, leading backslashes are removed only if +# followed by a markup character (<tt><*_+</tt>), a backslash, or a known link +# reference (a known class or method). So in the example above, the backslash +# of <tt>\S</tt> would be removed if there was a class or module named +S+ in +# the current context. +# +# This behavior is inherited from RDoc version 1, and has been kept for +# compatibility with existing RDoc documentation. +# +# === Conversion of characters +# +# HTML will convert two/three dashes to an em-dash. Other common characters are +# converted as well: +# +# em-dash:: -- or --- +# ellipsis:: ... +# +# single quotes:: 'text' or `text' +# double quotes:: "text" or ``text'' +# +# copyright:: (c) +# registered trademark:: (r) +# +# produces: +# +# em-dash:: -- or --- +# ellipsis:: ... +# +# single quotes:: 'text' or `text' +# double quotes:: "text" or ``text'' +# +# copyright:: (c) +# registered trademark:: (r) +# +# +# == Documenting Source Code +# +# Comment blocks can be written fairly naturally, either using <tt>#</tt> on +# successive lines of the comment, or by including the comment in +# a <tt>=begin</tt>/<tt>=end</tt> block. If you use the latter form, +# the <tt>=begin</tt> line _must_ be flagged with an +rdoc+ tag: +# +# =begin rdoc +# Documentation to be processed by RDoc. +# +# ... +# =end +# +# RDoc stops processing comments if it finds a comment line starting +# with <tt>--</tt> right after the <tt>#</tt> character (otherwise, +# it will be treated as a rule if it has three dashes or more). +# This can be used to separate external from internal comments, +# or to stop a comment being associated with a method, class, or module. +# Commenting can be turned back on with a line that starts with <tt>++</tt>. +# +# ## +# # Extract the age and calculate the date-of-birth. +# #-- +# # FIXME: fails if the birthday falls on February 29th +# #++ +# # The DOB is returned as a Time object. +# +# def get_dob(person) +# # ... +# end +# +# Names of classes, files, and any method names containing an underscore or +# preceded by a hash character are automatically linked from comment text to +# their description. This linking works inside the current class or module, +# and with ancestor methods (in included modules or in the superclass). +# +# Method parameter lists are extracted and displayed with the method +# description. If a method calls +yield+, then the parameters passed to yield +# will also be displayed: +# +# def fred +# ... +# yield line, address +# +# This will get documented as: +# +# fred() { |line, address| ... } +# +# You can override this using a comment containing ':yields: ...' immediately +# after the method definition +# +# def fred # :yields: index, position +# # ... +# +# yield line, address +# +# which will get documented as +# +# fred() { |index, position| ... } +# +# +:yields:+ is an example of a documentation directive. These appear +# immediately after the start of the document element they are modifying. +# +# RDoc automatically cross-references words with underscores or camel-case. +# To suppress cross-references, prefix the word with a \ character. To +# include special characters like "<tt>\n</tt>", you'll need to use +# two \ characters in normal text, but only one in \<tt> text: +# +# "\\n" or "<tt>\n</tt>" +# +# produces: +# +# "\\n" or "<tt>\n</tt>" +# +# == Directives +# +# Directives are keywords surrounded by ":" characters. +# +# === Controlling what is documented +# +# [+:nodoc:+ / <tt>:nodoc: all</tt>] +# This directive prevents documentation for the element from +# being generated. For classes and modules, methods, aliases, +# constants, and attributes directly within the affected class or +# module also will be omitted. By default, though, modules and +# classes within that class or module _will_ be documented. This is +# turned off by adding the +all+ modifier. +# +# module MyModule # :nodoc: +# class Input +# end +# end +# +# module OtherModule # :nodoc: all +# class Output +# end +# end +# +# In the above code, only class <tt>MyModule::Input</tt> will be documented. +# +# The +:nodoc:+ directive, like +:enddoc:+, +:stopdoc:+ and +:startdoc:+ +# presented below, is local to the current file: if you do not want to +# document a module that appears in several files, specify +:nodoc:+ on each +# appearance, at least once per file. +# +# [+:stopdoc:+ / +:startdoc:+] +# Stop and start adding new documentation elements to the current container. +# For example, if a class has a number of constants that you don't want to +# document, put a +:stopdoc:+ before the first, and a +:startdoc:+ after the +# last. If you don't specify a +:startdoc:+ by the end of the container, +# disables documentation for the rest of the current file. +# +# [+:doc:+] +# Forces a method or attribute to be documented even if it wouldn't be +# otherwise. Useful if, for example, you want to include documentation of a +# particular private method. +# +# [+:enddoc:+] +# Document nothing further at the current level: directives +:startdoc:+ and +# +:doc:+ that appear after this will not be honored for the current container +# (file, class or module), in the current file. +# +# [+:notnew:+ / +:not_new:+ / +:not-new:+ ] +# Only applicable to the +initialize+ instance method. Normally RDoc +# assumes that the documentation and parameters for +initialize+ are +# actually for the +new+ method, and so fakes out a +new+ for the class. +# The +:notnew:+ directive stops this. Remember that +initialize+ is private, +# so you won't see the documentation unless you use the +-a+ command line +# option. +# +# === Method arguments +# +# [+:arg:+ or +:args:+ _parameters_] +# Overrides the default argument handling with exactly these parameters. +# +# ## +# # :args: a, b +# +# def some_method(*a) +# end +# +# [+:yield:+ or +:yields:+ _parameters_] +# Overrides the default yield discovery with these parameters. +# +# ## +# # :yields: key, value +# +# def each_thing &block +# @things.each(&block) +# end +# +# [+:call-seq:+] +# Lines up to the next blank line or lines with a common prefix in the +# comment are treated as the method's calling sequence, overriding the +# default parsing of method parameters and yield arguments. +# +# Multiple lines may be used. +# +# # :call-seq: +# # ARGF.readlines(sep=$/) -> array +# # ARGF.readlines(limit) -> array +# # ARGF.readlines(sep, limit) -> array +# # +# # ARGF.to_a(sep=$/) -> array +# # ARGF.to_a(limit) -> array +# # ARGF.to_a(sep, limit) -> array +# # +# # The remaining lines are documentation ... +# +# === Sections +# +# Sections allow you to group methods in a class into sensible containers. If +# you use the sections 'Public', 'Internal' and 'Deprecated' (the three +# allowed method statuses from TomDoc) the sections will be displayed in that +# order placing the most useful methods at the top. Otherwise, sections will +# be displayed in alphabetical order. +# +# [+:category:+ _section_] +# Adds this item to the named +section+ overriding the current section. Use +# this to group methods by section in RDoc output while maintaining a +# sensible ordering (like alphabetical). +# +# # :category: Utility Methods +# # +# # CGI escapes +text+ +# +# def convert_string text +# CGI.escapeHTML text +# end +# +# An empty category will place the item in the default category: +# +# # :category: +# # +# # This method is in the default category +# +# def some_method +# # ... +# end +# +# Unlike the :section: directive, :category: is not sticky. The category +# only applies to the item immediately following the comment. +# +# Use the :section: directive to provide introductory text for a section of +# documentation. +# +# [+:section:+ _title_] +# Provides section introductory text in RDoc output. The title following +# +:section:+ is used as the section name and the remainder of the comment +# containing the section is used as introductory text. A section's comment +# block must be separated from following comment blocks. Use an empty title +# to switch to the default section. +# +# The :section: directive is sticky, so subsequent methods, aliases, +# attributes, and classes will be contained in this section until the +# section is changed. The :category: directive will override the :section: +# directive. +# +# A :section: comment block may have one or more lines before the :section: +# directive. These will be removed, and any identical lines at the end of +# the block are also removed. This allows you to add visual cues to the +# section. +# +# Example: +# +# # ---------------------------------------- +# # :section: My Section +# # This is the section that I wrote. +# # See it glisten in the noon-day sun. +# # ---------------------------------------- +# +# ## +# # Comment for some_method +# +# def some_method +# # ... +# end +# +# === Other directives +# +# [+:markup:+ _type_] +# Overrides the default markup type for this comment with the specified +# markup type. For Ruby files, if the first comment contains this directive +# it is applied automatically to all comments in the file. +# +# Unless you are converting between markup formats you should use a +# <code>.rdoc_options</code> file to specify the default documentation +# format for your entire project. See RDoc::Options@Saved+Options for +# instructions. +# +# At the top of a file the +:markup:+ directive applies to the entire file: +# +# # coding: UTF-8 +# # :markup: TomDoc +# +# # TomDoc comment here ... +# +# class MyClass +# # ... +# +# For just one comment: +# +# # ... +# end +# +# # :markup: RDoc +# # +# # This is a comment in RDoc markup format ... +# +# def some_method +# # ... +# +# See Markup@CONTRIBUTING for instructions on adding a new markup format. +# +# [+:include:+ _filename_] +# Include the contents of the named file at this point. This directive +# must appear alone on one line, possibly preceded by spaces. In this +# position, it can be escaped with a \ in front of the first colon. +# +# The file will be searched for in the directories listed by the +--include+ +# option, or in the current directory by default. The contents of the file +# will be shifted to have the same indentation as the ':' at the start of +# the +:include:+ directive. +# +# [+:title:+ _text_] +# Sets the title for the document. Equivalent to the <tt>--title</tt> +# command line parameter. (The command line parameter overrides any :title: +# directive in the source). +# +# [+:main:+ _name_] +# Equivalent to the <tt>--main</tt> command line parameter. +# +#-- +# Original Author:: Dave Thomas, dave@pragmaticprogrammer.com +# License:: Ruby license + +class RDoc::Markup + + ## + # An AttributeManager which handles inline markup. + + attr_reader :attribute_manager + + ## + # Parses +str+ into an RDoc::Markup::Document. + + def self.parse str + RDoc::Markup::Parser.parse str + rescue RDoc::Markup::Parser::Error => e + $stderr.puts <<-EOF +While parsing markup, RDoc encountered a #{e.class}: + +#{e} +\tfrom #{e.backtrace.join "\n\tfrom "} + +---8<--- +#{text} +---8<--- + +RDoc #{RDoc::VERSION} + +Ruby #{RUBY_VERSION}-p#{RUBY_PATCHLEVEL} #{RUBY_RELEASE_DATE} + +Please file a bug report with the above information at: + +https://github.com/rdoc/rdoc/issues + + EOF + raise + end + + ## + # Take a block of text and use various heuristics to determine its + # structure (paragraphs, lists, and so on). Invoke an event handler as we + # identify significant chunks. + + def initialize attribute_manager = nil + @attribute_manager = attribute_manager || RDoc::Markup::AttributeManager.new + @output = nil + end + + ## + # Add to the sequences used to add formatting to an individual word (such + # as *bold*). Matching entries will generate attributes that the output + # formatters can recognize by their +name+. + + def add_word_pair(start, stop, name) + @attribute_manager.add_word_pair(start, stop, name) + end + + ## + # Add to the sequences recognized as general markup. + + def add_html(tag, name) + @attribute_manager.add_html(tag, name) + end + + ## + # Add to other inline sequences. For example, we could add WikiWords using + # something like: + # + # parser.add_special(/\b([A-Z][a-z]+[A-Z]\w+)/, :WIKIWORD) + # + # Each wiki word will be presented to the output formatter via the + # accept_special method. + + def add_special(pattern, name) + @attribute_manager.add_special(pattern, name) + end + + ## + # We take +input+, parse it if necessary, then invoke the output +formatter+ + # using a Visitor to render the result. + + def convert input, formatter + document = case input + when RDoc::Markup::Document then + input + else + RDoc::Markup::Parser.parse input + end + + document.accept formatter + end + + autoload :Parser, 'rdoc/markup/parser' + autoload :PreProcess, 'rdoc/markup/pre_process' + + # Inline markup classes + autoload :AttrChanger, 'rdoc/markup/attr_changer' + autoload :AttrSpan, 'rdoc/markup/attr_span' + autoload :Attributes, 'rdoc/markup/attributes' + autoload :AttributeManager, 'rdoc/markup/attribute_manager' + autoload :Special, 'rdoc/markup/special' + + # RDoc::Markup AST + autoload :BlankLine, 'rdoc/markup/blank_line' + autoload :BlockQuote, 'rdoc/markup/block_quote' + autoload :Document, 'rdoc/markup/document' + autoload :HardBreak, 'rdoc/markup/hard_break' + autoload :Heading, 'rdoc/markup/heading' + autoload :Include, 'rdoc/markup/include' + autoload :IndentedParagraph, 'rdoc/markup/indented_paragraph' + autoload :List, 'rdoc/markup/list' + autoload :ListItem, 'rdoc/markup/list_item' + autoload :Paragraph, 'rdoc/markup/paragraph' + autoload :Raw, 'rdoc/markup/raw' + autoload :Rule, 'rdoc/markup/rule' + autoload :Verbatim, 'rdoc/markup/verbatim' + + # Formatters + autoload :Formatter, 'rdoc/markup/formatter' + autoload :FormatterTestCase, 'rdoc/markup/formatter_test_case' + autoload :TextFormatterTestCase, 'rdoc/markup/text_formatter_test_case' + + autoload :ToAnsi, 'rdoc/markup/to_ansi' + autoload :ToBs, 'rdoc/markup/to_bs' + autoload :ToHtml, 'rdoc/markup/to_html' + autoload :ToHtmlCrossref, 'rdoc/markup/to_html_crossref' + autoload :ToHtmlSnippet, 'rdoc/markup/to_html_snippet' + autoload :ToLabel, 'rdoc/markup/to_label' + autoload :ToMarkdown, 'rdoc/markup/to_markdown' + autoload :ToRdoc, 'rdoc/markup/to_rdoc' + autoload :ToTableOfContents, 'rdoc/markup/to_table_of_contents' + autoload :ToTest, 'rdoc/markup/to_test' + autoload :ToTtOnly, 'rdoc/markup/to_tt_only' + +end + diff --git a/jni/ruby/lib/rdoc/markup/attr_changer.rb b/jni/ruby/lib/rdoc/markup/attr_changer.rb new file mode 100644 index 0000000..1772f18 --- /dev/null +++ b/jni/ruby/lib/rdoc/markup/attr_changer.rb @@ -0,0 +1,22 @@ +class RDoc::Markup + + AttrChanger = Struct.new :turn_on, :turn_off # :nodoc: + +end + +## +# An AttrChanger records a change in attributes. It contains a bitmap of the +# attributes to turn on, and a bitmap of those to turn off. + +class RDoc::Markup::AttrChanger + + def to_s # :nodoc: + "Attr: +#{turn_on}/-#{turn_off}" + end + + def inspect # :nodoc: + '+%d/-%d' % [turn_on, turn_off] + end + +end + diff --git a/jni/ruby/lib/rdoc/markup/attr_span.rb b/jni/ruby/lib/rdoc/markup/attr_span.rb new file mode 100644 index 0000000..b5c1b3b --- /dev/null +++ b/jni/ruby/lib/rdoc/markup/attr_span.rb @@ -0,0 +1,29 @@ +## +# An array of attributes which parallels the characters in a string. + +class RDoc::Markup::AttrSpan + + ## + # Creates a new AttrSpan for +length+ characters + + def initialize(length) + @attrs = Array.new(length, 0) + end + + ## + # Toggles +bits+ from +start+ to +length+ + def set_attrs(start, length, bits) + for i in start ... (start+length) + @attrs[i] |= bits + end + end + + ## + # Accesses flags for character +n+ + + def [](n) + @attrs[n] + end + +end + diff --git a/jni/ruby/lib/rdoc/markup/attribute_manager.rb b/jni/ruby/lib/rdoc/markup/attribute_manager.rb new file mode 100644 index 0000000..ce4ac76 --- /dev/null +++ b/jni/ruby/lib/rdoc/markup/attribute_manager.rb @@ -0,0 +1,343 @@ +## +# Manages changes of attributes in a block of text + +class RDoc::Markup::AttributeManager + + ## + # The NUL character + + NULL = "\000".freeze + + #-- + # We work by substituting non-printing characters in to the text. For now + # I'm assuming that I can substitute a character in the range 0..8 for a 7 + # bit character without damaging the encoded string, but this might be + # optimistic + #++ + + A_PROTECT = 004 # :nodoc: + + ## + # Special mask character to prevent inline markup handling + + PROTECT_ATTR = A_PROTECT.chr # :nodoc: + + ## + # The attributes enabled for this markup object. + + attr_reader :attributes + + ## + # This maps delimiters that occur around words (such as *bold* or +tt+) + # where the start and end delimiters and the same. This lets us optimize + # the regexp + + attr_reader :matching_word_pairs + + ## + # And this is used when the delimiters aren't the same. In this case the + # hash maps a pattern to the attribute character + + attr_reader :word_pair_map + + ## + # This maps HTML tags to the corresponding attribute char + + attr_reader :html_tags + + ## + # A \ in front of a character that would normally be processed turns off + # processing. We do this by turning \< into <#{PROTECT} + + attr_reader :protectable + + ## + # And this maps _special_ sequences to a name. A special sequence is + # something like a WikiWord + + attr_reader :special + + ## + # Creates a new attribute manager that understands bold, emphasized and + # teletype text. + + def initialize + @html_tags = {} + @matching_word_pairs = {} + @protectable = %w[<] + @special = [] + @word_pair_map = {} + @attributes = RDoc::Markup::Attributes.new + + add_word_pair "*", "*", :BOLD + add_word_pair "_", "_", :EM + add_word_pair "+", "+", :TT + + add_html "em", :EM + add_html "i", :EM + add_html "b", :BOLD + add_html "tt", :TT + add_html "code", :TT + end + + ## + # Return an attribute object with the given turn_on and turn_off bits set + + def attribute(turn_on, turn_off) + RDoc::Markup::AttrChanger.new turn_on, turn_off + end + + ## + # Changes the current attribute from +current+ to +new+ + + def change_attribute current, new + diff = current ^ new + attribute(new & diff, current & diff) + end + + ## + # Used by the tests to change attributes by name from +current_set+ to + # +new_set+ + + def changed_attribute_by_name current_set, new_set + current = new = 0 + current_set.each do |name| + current |= @attributes.bitmap_for(name) + end + + new_set.each do |name| + new |= @attributes.bitmap_for(name) + end + + change_attribute(current, new) + end + + ## + # Copies +start_pos+ to +end_pos+ from the current string + + def copy_string(start_pos, end_pos) + res = @str[start_pos...end_pos] + res.gsub!(/\000/, '') + res + end + + ## + # Map attributes like <b>text</b>to the sequence + # \001\002<char>\001\003<char>, where <char> is a per-attribute specific + # character + + def convert_attrs(str, attrs) + # first do matching ones + tags = @matching_word_pairs.keys.join("") + + re = /(^|\W)([#{tags}])([#\\]?[\w:.\/-]+?\S?)\2(\W|$)/ + + 1 while str.gsub!(re) do + attr = @matching_word_pairs[$2] + attrs.set_attrs($`.length + $1.length + $2.length, $3.length, attr) + $1 + NULL * $2.length + $3 + NULL * $2.length + $4 + end + + # then non-matching + unless @word_pair_map.empty? then + @word_pair_map.each do |regexp, attr| + str.gsub!(regexp) { + attrs.set_attrs($`.length + $1.length, $2.length, attr) + NULL * $1.length + $2 + NULL * $3.length + } + end + end + end + + ## + # Converts HTML tags to RDoc attributes + + def convert_html(str, attrs) + tags = @html_tags.keys.join '|' + + 1 while str.gsub!(/<(#{tags})>(.*?)<\/\1>/i) { + attr = @html_tags[$1.downcase] + html_length = $1.length + 2 + seq = NULL * html_length + attrs.set_attrs($`.length + html_length, $2.length, attr) + seq + $2 + seq + NULL + } + end + + ## + # Converts special sequences to RDoc attributes + + def convert_specials str, attrs + @special.each do |regexp, attribute| + str.scan(regexp) do + capture = $~.size == 1 ? 0 : 1 + + s, e = $~.offset capture + + attrs.set_attrs s, e - s, attribute | @attributes.special + end + end + end + + ## + # Escapes special sequences of text to prevent conversion to RDoc + + def mask_protected_sequences + # protect __send__, __FILE__, etc. + @str.gsub!(/__([a-z]+)__/i, + "_#{PROTECT_ATTR}_#{PROTECT_ATTR}\\1_#{PROTECT_ATTR}_#{PROTECT_ATTR}") + @str.gsub!(/(\A|[^\\])\\([#{Regexp.escape @protectable.join}])/m, + "\\1\\2#{PROTECT_ATTR}") + @str.gsub!(/\\(\\[#{Regexp.escape @protectable.join}])/m, "\\1") + end + + ## + # Unescapes special sequences of text + + def unmask_protected_sequences + @str.gsub!(/(.)#{PROTECT_ATTR}/, "\\1\000") + end + + ## + # Adds a markup class with +name+ for words wrapped in the +start+ and + # +stop+ character. To make words wrapped with "*" bold: + # + # am.add_word_pair '*', '*', :BOLD + + def add_word_pair(start, stop, name) + raise ArgumentError, "Word flags may not start with '<'" if + start[0,1] == '<' + + bitmap = @attributes.bitmap_for name + + if start == stop then + @matching_word_pairs[start] = bitmap + else + pattern = /(#{Regexp.escape start})(\S+)(#{Regexp.escape stop})/ + @word_pair_map[pattern] = bitmap + end + + @protectable << start[0,1] + @protectable.uniq! + end + + ## + # Adds a markup class with +name+ for words surrounded by HTML tag +tag+. + # To process emphasis tags: + # + # am.add_html 'em', :EM + + def add_html(tag, name) + @html_tags[tag.downcase] = @attributes.bitmap_for name + end + + ## + # Adds a special handler for +pattern+ with +name+. A simple URL handler + # would be: + # + # @am.add_special(/((https?:)\S+\w)/, :HYPERLINK) + + def add_special pattern, name + @special << [pattern, @attributes.bitmap_for(name)] + end + + ## + # Processes +str+ converting attributes, HTML and specials + + def flow str + @str = str + + mask_protected_sequences + + @attrs = RDoc::Markup::AttrSpan.new @str.length + + convert_attrs @str, @attrs + convert_html @str, @attrs + convert_specials @str, @attrs + + unmask_protected_sequences + + split_into_flow + end + + ## + # Debug method that prints a string along with its attributes + + def display_attributes + puts + puts @str.tr(NULL, "!") + bit = 1 + 16.times do |bno| + line = "" + @str.length.times do |i| + if (@attrs[i] & bit) == 0 + line << " " + else + if bno.zero? + line << "S" + else + line << ("%d" % (bno+1)) + end + end + end + puts(line) unless line =~ /^ *$/ + bit <<= 1 + end + end + + ## + # Splits the string into chunks by attribute change + + def split_into_flow + res = [] + current_attr = 0 + + str_len = @str.length + + # skip leading invisible text + i = 0 + i += 1 while i < str_len and @str[i].chr == "\0" + start_pos = i + + # then scan the string, chunking it on attribute changes + while i < str_len + new_attr = @attrs[i] + if new_attr != current_attr + if i > start_pos + res << copy_string(start_pos, i) + start_pos = i + end + + res << change_attribute(current_attr, new_attr) + current_attr = new_attr + + if (current_attr & @attributes.special) != 0 then + i += 1 while + i < str_len and (@attrs[i] & @attributes.special) != 0 + + res << RDoc::Markup::Special.new(current_attr, + copy_string(start_pos, i)) + start_pos = i + next + end + end + + # move on, skipping any invisible characters + begin + i += 1 + end while i < str_len and @str[i].chr == "\0" + end + + # tidy up trailing text + if start_pos < str_len + res << copy_string(start_pos, str_len) + end + + # and reset to all attributes off + res << change_attribute(current_attr, 0) if current_attr != 0 + + res + end + +end + diff --git a/jni/ruby/lib/rdoc/markup/attributes.rb b/jni/ruby/lib/rdoc/markup/attributes.rb new file mode 100644 index 0000000..3423f10 --- /dev/null +++ b/jni/ruby/lib/rdoc/markup/attributes.rb @@ -0,0 +1,70 @@ +## +# We manage a set of attributes. Each attribute has a symbol name and a bit +# value. + +class RDoc::Markup::Attributes + + ## + # The special attribute type. See RDoc::Markup#add_special + + attr_reader :special + + ## + # Creates a new attributes set. + + def initialize + @special = 1 + + @name_to_bitmap = [ + [:_SPECIAL_, @special], + ] + + @next_bitmap = @special << 1 + end + + ## + # Returns a unique bit for +name+ + + def bitmap_for name + bitmap = @name_to_bitmap.assoc name + + unless bitmap then + bitmap = @next_bitmap + @next_bitmap <<= 1 + @name_to_bitmap << [name, bitmap] + else + bitmap = bitmap.last + end + + bitmap + end + + ## + # Returns a string representation of +bitmap+ + + def as_string bitmap + return 'none' if bitmap.zero? + res = [] + + @name_to_bitmap.each do |name, bit| + res << name if (bitmap & bit) != 0 + end + + res.join ',' + end + + ## + # yields each attribute name in +bitmap+ + + def each_name_of bitmap + return enum_for __method__, bitmap unless block_given? + + @name_to_bitmap.each do |name, bit| + next if bit == @special + + yield name.to_s if (bitmap & bit) != 0 + end + end + +end + diff --git a/jni/ruby/lib/rdoc/markup/blank_line.rb b/jni/ruby/lib/rdoc/markup/blank_line.rb new file mode 100644 index 0000000..5da0ac8 --- /dev/null +++ b/jni/ruby/lib/rdoc/markup/blank_line.rb @@ -0,0 +1,27 @@ +## +# An empty line. This class is a singleton. + +class RDoc::Markup::BlankLine + + @instance = new + + ## + # RDoc::Markup::BlankLine is a singleton + + def self.new + @instance + end + + ## + # Calls #accept_blank_line on +visitor+ + + def accept visitor + visitor.accept_blank_line self + end + + def pretty_print q # :nodoc: + q.text 'blankline' + end + +end + diff --git a/jni/ruby/lib/rdoc/markup/block_quote.rb b/jni/ruby/lib/rdoc/markup/block_quote.rb new file mode 100644 index 0000000..552f0c4 --- /dev/null +++ b/jni/ruby/lib/rdoc/markup/block_quote.rb @@ -0,0 +1,14 @@ +## +# A quoted section which contains markup items. + +class RDoc::Markup::BlockQuote < RDoc::Markup::Raw + + ## + # Calls #accept_block_quote on +visitor+ + + def accept visitor + visitor.accept_block_quote self + end + +end + diff --git a/jni/ruby/lib/rdoc/markup/document.rb b/jni/ruby/lib/rdoc/markup/document.rb new file mode 100644 index 0000000..be93d80 --- /dev/null +++ b/jni/ruby/lib/rdoc/markup/document.rb @@ -0,0 +1,164 @@ +## +# A Document containing lists, headings, paragraphs, etc. + +class RDoc::Markup::Document + + include Enumerable + + ## + # The file this document was created from. See also + # RDoc::ClassModule#add_comment + + attr_reader :file + + ## + # If a heading is below the given level it will be omitted from the + # table_of_contents + + attr_accessor :omit_headings_below + + ## + # The parts of the Document + + attr_reader :parts + + ## + # Creates a new Document with +parts+ + + def initialize *parts + @parts = [] + @parts.concat parts + + @file = nil + @omit_headings_from_table_of_contents_below = nil + end + + ## + # Appends +part+ to the document + + def << part + case part + when RDoc::Markup::Document then + unless part.empty? then + parts.concat part.parts + parts << RDoc::Markup::BlankLine.new + end + when String then + raise ArgumentError, + "expected RDoc::Markup::Document and friends, got String" unless + part.empty? + else + parts << part + end + end + + def == other # :nodoc: + self.class == other.class and + @file == other.file and + @parts == other.parts + end + + ## + # Runs this document and all its #items through +visitor+ + + def accept visitor + visitor.start_accepting + + visitor.accept_document self + + visitor.end_accepting + end + + ## + # Concatenates the given +parts+ onto the document + + def concat parts + self.parts.concat parts + end + + ## + # Enumerator for the parts of this document + + def each &block + @parts.each(&block) + end + + ## + # Does this document have no parts? + + def empty? + @parts.empty? or (@parts.length == 1 and merged? and @parts.first.empty?) + end + + ## + # The file this Document was created from. + + def file= location + @file = case location + when RDoc::TopLevel then + location.relative_name + else + location + end + end + + ## + # When this is a collection of documents (#file is not set and this document + # contains only other documents as its direct children) #merge replaces + # documents in this class with documents from +other+ when the file matches + # and adds documents from +other+ when the files do not. + # + # The information in +other+ is preferred over the receiver + + def merge other + if empty? then + @parts = other.parts + return self + end + + other.parts.each do |other_part| + self.parts.delete_if do |self_part| + self_part.file and self_part.file == other_part.file + end + + self.parts << other_part + end + + self + end + + ## + # Does this Document contain other Documents? + + def merged? + RDoc::Markup::Document === @parts.first + end + + def pretty_print q # :nodoc: + start = @file ? "[doc (#{@file}): " : '[doc: ' + + q.group 2, start, ']' do + q.seplist @parts do |part| + q.pp part + end + end + end + + ## + # Appends +parts+ to the document + + def push *parts + self.parts.concat parts + end + + ## + # Returns an Array of headings in the document. + # + # Require 'rdoc/markup/formatter' before calling this method. + + def table_of_contents + accept RDoc::Markup::ToTableOfContents.to_toc + end + +end + diff --git a/jni/ruby/lib/rdoc/markup/formatter.rb b/jni/ruby/lib/rdoc/markup/formatter.rb new file mode 100644 index 0000000..7661c95 --- /dev/null +++ b/jni/ruby/lib/rdoc/markup/formatter.rb @@ -0,0 +1,264 @@ +## +# Base class for RDoc markup formatters +# +# Formatters are a visitor that converts an RDoc::Markup tree (from a comment) +# into some kind of output. RDoc ships with formatters for converting back to +# rdoc, ANSI text, HTML, a Table of Contents and other formats. +# +# If you'd like to write your own Formatter use +# RDoc::Markup::FormatterTestCase. If you're writing a text-output formatter +# use RDoc::Markup::TextFormatterTestCase which provides extra test cases. + +class RDoc::Markup::Formatter + + ## + # Tag for inline markup containing a +bit+ for the bitmask and the +on+ and + # +off+ triggers. + + InlineTag = Struct.new(:bit, :on, :off) + + ## + # Converts a target url to one that is relative to a given path + + def self.gen_relative_url path, target + from = File.dirname path + to, to_file = File.split target + + from = from.split "/" + to = to.split "/" + + from.delete '.' + to.delete '.' + + while from.size > 0 and to.size > 0 and from[0] == to[0] do + from.shift + to.shift + end + + from.fill ".." + from.concat to + from << to_file + File.join(*from) + end + + ## + # Creates a new Formatter + + def initialize options, markup = nil + @options = options + + @markup = markup || RDoc::Markup.new + @am = @markup.attribute_manager + @am.add_special(/<br>/, :HARD_BREAK) + + @attributes = @am.attributes + + @attr_tags = [] + + @in_tt = 0 + @tt_bit = @attributes.bitmap_for :TT + + @hard_break = '' + @from_path = '.' + end + + ## + # Adds +document+ to the output + + def accept_document document + document.parts.each do |item| + case item + when RDoc::Markup::Document then # HACK + accept_document item + else + item.accept self + end + end + end + + ## + # Adds a special for links of the form rdoc-...: + + def add_special_RDOCLINK + @markup.add_special(/rdoc-[a-z]+:[^\s\]]+/, :RDOCLINK) + end + + ## + # Adds a special for links of the form {<text>}[<url>] and <word>[<url>] + + def add_special_TIDYLINK + @markup.add_special(/(?: + \{.*?\} | # multi-word label + \b[^\s{}]+? # single-word label + ) + + \[\S+?\] # link target + /x, :TIDYLINK) + end + + ## + # Add a new set of tags for an attribute. We allow separate start and end + # tags for flexibility + + def add_tag(name, start, stop) + attr = @attributes.bitmap_for name + @attr_tags << InlineTag.new(attr, start, stop) + end + + ## + # Allows +tag+ to be decorated with additional information. + + def annotate(tag) + tag + end + + ## + # Marks up +content+ + + def convert content + @markup.convert content, self + end + + ## + # Converts flow items +flow+ + + def convert_flow(flow) + res = [] + + flow.each do |item| + case item + when String then + res << convert_string(item) + when RDoc::Markup::AttrChanger then + off_tags res, item + on_tags res, item + when RDoc::Markup::Special then + res << convert_special(item) + else + raise "Unknown flow element: #{item.inspect}" + end + end + + res.join + end + + ## + # Converts added specials. See RDoc::Markup#add_special + + def convert_special special + return special.text if in_tt? + + handled = false + + @attributes.each_name_of special.type do |name| + method_name = "handle_special_#{name}" + + if respond_to? method_name then + special.text = send method_name, special + handled = true + end + end + + unless handled then + special_name = @attributes.as_string special.type + + raise RDoc::Error, "Unhandled special #{special_name}: #{special}" + end + + special.text + end + + ## + # Converts a string to be fancier if desired + + def convert_string string + string + end + + ## + # Use ignore in your subclass to ignore the content of a node. + # + # ## + # # We don't support raw nodes in ToNoRaw + # + # alias accept_raw ignore + + def ignore *node + end + + ## + # Are we currently inside tt tags? + + def in_tt? + @in_tt > 0 + end + + ## + # Turns on tags for +item+ on +res+ + + def on_tags res, item + attr_mask = item.turn_on + return if attr_mask.zero? + + @attr_tags.each do |tag| + if attr_mask & tag.bit != 0 then + res << annotate(tag.on) + @in_tt += 1 if tt? tag + end + end + end + + ## + # Turns off tags for +item+ on +res+ + + def off_tags res, item + attr_mask = item.turn_off + return if attr_mask.zero? + + @attr_tags.reverse_each do |tag| + if attr_mask & tag.bit != 0 then + @in_tt -= 1 if tt? tag + res << annotate(tag.off) + end + end + end + + ## + # Extracts and a scheme, url and an anchor id from +url+ and returns them. + + def parse_url url + case url + when /^rdoc-label:([^:]*)(?::(.*))?/ then + scheme = 'link' + path = "##{$1}" + id = " id=\"#{$2}\"" if $2 + when /([A-Za-z]+):(.*)/ then + scheme = $1.downcase + path = $2 + when /^#/ then + else + scheme = 'http' + path = url + url = url + end + + if scheme == 'link' then + url = if path[0, 1] == '#' then # is this meaningful? + path + else + self.class.gen_relative_url @from_path, path + end + end + + [scheme, url, id] + end + + ## + # Is +tag+ a tt tag? + + def tt? tag + tag.bit == @tt_bit + end + +end + diff --git a/jni/ruby/lib/rdoc/markup/formatter_test_case.rb b/jni/ruby/lib/rdoc/markup/formatter_test_case.rb new file mode 100644 index 0000000..6616a75 --- /dev/null +++ b/jni/ruby/lib/rdoc/markup/formatter_test_case.rb @@ -0,0 +1,767 @@ +require 'minitest/unit' + +## +# Test case for creating new RDoc::Markup formatters. See +# test/test_rdoc_markup_to_*.rb for examples. +# +# This test case adds a variety of tests to your subclass when +# #add_visitor_tests is called. Most tests set up a scenario then call a +# method you will provide to perform the assertion on the output. +# +# Your subclass must instantiate a visitor and assign it to <tt>@to</tt>. +# +# For example, test_accept_blank_line sets up a RDoc::Markup::BlockLine then +# calls accept_blank_line on your visitor. You are responsible for asserting +# that the output is correct. +# +# Example: +# +# class TestRDocMarkupToNewFormat < RDoc::Markup::FormatterTestCase +# +# add_visitor_tests +# +# def setup +# super +# +# @to = RDoc::Markup::ToNewFormat.new +# end +# +# def accept_blank_line +# assert_equal :junk, @to.res.join +# end +# +# # ... +# +# end + +class RDoc::Markup::FormatterTestCase < RDoc::TestCase + + ## + # Call #setup when inheriting from this test case. + # + # Provides the following instance variables: + # + # +@m+:: RDoc::Markup.new + # +@RM+:: RDoc::Markup # to reduce typing + # +@bullet_list+:: @RM::List.new :BULLET, # ... + # +@label_list+:: @RM::List.new :LABEL, # ... + # +@lalpha_list+:: @RM::List.new :LALPHA, # ... + # +@note_list+:: @RM::List.new :NOTE, # ... + # +@number_list+:: @RM::List.new :NUMBER, # ... + # +@ualpha_list+:: @RM::List.new :UALPHA, # ... + + def setup + super + + @options = RDoc::Options.new + + @m = @RM.new + + @bullet_list = @RM::List.new(:BULLET, + @RM::ListItem.new(nil, @RM::Paragraph.new('l1')), + @RM::ListItem.new(nil, @RM::Paragraph.new('l2'))) + + @label_list = @RM::List.new(:LABEL, + @RM::ListItem.new('cat', @RM::Paragraph.new('cats are cool')), + @RM::ListItem.new('dog', @RM::Paragraph.new('dogs are cool too'))) + + @lalpha_list = @RM::List.new(:LALPHA, + @RM::ListItem.new(nil, @RM::Paragraph.new('l1')), + @RM::ListItem.new(nil, @RM::Paragraph.new('l2'))) + + @note_list = @RM::List.new(:NOTE, + @RM::ListItem.new('cat', @RM::Paragraph.new('cats are cool')), + @RM::ListItem.new('dog', @RM::Paragraph.new('dogs are cool too'))) + + @number_list = @RM::List.new(:NUMBER, + @RM::ListItem.new(nil, @RM::Paragraph.new('l1')), + @RM::ListItem.new(nil, @RM::Paragraph.new('l2'))) + + @ualpha_list = @RM::List.new(:UALPHA, + @RM::ListItem.new(nil, @RM::Paragraph.new('l1')), + @RM::ListItem.new(nil, @RM::Paragraph.new('l2'))) + end + + ## + # Call to add the visitor tests to your test case + + def self.add_visitor_tests + class_eval do + + ## + # Calls start_accepting which needs to verify startup state + + def test_start_accepting + @to.start_accepting + + start_accepting + end + + ## + # Calls end_accepting on your test case which needs to call + # <tt>@to.end_accepting</tt> and verify document generation + + def test_end_accepting + @to.start_accepting + @to.res << 'hi' + + end_accepting + end + + ## + # Calls accept_blank_line + + def test_accept_blank_line + @to.start_accepting + + @to.accept_blank_line @RM::BlankLine.new + + accept_blank_line + end + + ## + # Calls accept_block_quote + + def test_accept_block_quote + @to.start_accepting + + @to.accept_block_quote block para 'quote' + + accept_block_quote + end + ## + # Test case that calls <tt>@to.accept_document</tt> + + def test_accept_document + @to.start_accepting + @to.accept_document @RM::Document.new @RM::Paragraph.new 'hello' + + accept_document + end + + ## + # Calls accept_heading with a level 5 RDoc::Markup::Heading + + def test_accept_heading + @to.start_accepting + + @to.accept_heading @RM::Heading.new(5, 'Hello') + + accept_heading + end + + ## + # Calls accept_heading_1 with a level 1 RDoc::Markup::Heading + + def test_accept_heading_1 + @to.start_accepting + + @to.accept_heading @RM::Heading.new(1, 'Hello') + + accept_heading_1 + end + + ## + # Calls accept_heading_2 with a level 2 RDoc::Markup::Heading + + def test_accept_heading_2 + @to.start_accepting + + @to.accept_heading @RM::Heading.new(2, 'Hello') + + accept_heading_2 + end + + ## + # Calls accept_heading_3 with a level 3 RDoc::Markup::Heading + + def test_accept_heading_3 + # HACK this doesn't belong here + skip "No String#chars, upgrade your ruby" unless ''.respond_to? :chars + + @to.start_accepting + + @to.accept_heading @RM::Heading.new(3, 'Hello') + + accept_heading_3 + end + + ## + # Calls accept_heading_4 with a level 4 RDoc::Markup::Heading + + def test_accept_heading_4 + @to.start_accepting + + @to.accept_heading @RM::Heading.new(4, 'Hello') + + accept_heading_4 + end + + ## + # Calls accept_heading_b with a bold level 1 RDoc::Markup::Heading + + def test_accept_heading_b + @to.start_accepting + + @to.accept_heading @RM::Heading.new(1, '*Hello*') + + accept_heading_b + end + + ## + # Calls accept_heading_suppressed_crossref with a level 1 + # RDoc::Markup::Heading containing a suppressed crossref + + def test_accept_heading_suppressed_crossref # HACK to_html_crossref test + @to.start_accepting + + @to.accept_heading @RM::Heading.new(1, '\\Hello') + + accept_heading_suppressed_crossref + end + + ## + # Calls accept_paragraph + + def test_accept_paragraph + @to.start_accepting + + @to.accept_paragraph @RM::Paragraph.new('hi') + + accept_paragraph + end + + ## + # Calls accept_paragraph_b with a RDoc::Markup::Paragraph containing + # bold words + + def test_accept_paragraph_b + @to.start_accepting + + @to.accept_paragraph @RM::Paragraph.new('reg <b>bold words</b> reg') + + accept_paragraph_b + end + + ## + # Calls accept_paragraph_br with a RDoc::Markup::Paragraph containing + # a \<br> + + def test_accept_paragraph_br + @to.start_accepting + + @to.accept_paragraph para 'one<br>two' + + accept_paragraph_br + end + + ## + # Calls accept_paragraph with a Paragraph containing a hard break + + def test_accept_paragraph_break + @to.start_accepting + + @to.accept_paragraph para('hello', hard_break, 'world') + + accept_paragraph_break + end + + ## + # Calls accept_paragraph_i with a RDoc::Markup::Paragraph containing + # emphasized words + + def test_accept_paragraph_i + @to.start_accepting + + @to.accept_paragraph @RM::Paragraph.new('reg <em>italic words</em> reg') + + accept_paragraph_i + end + + ## + # Calls accept_paragraph_plus with a RDoc::Markup::Paragraph containing + # teletype words + + def test_accept_paragraph_plus + @to.start_accepting + + @to.accept_paragraph @RM::Paragraph.new('reg +teletype+ reg') + + accept_paragraph_plus + end + + ## + # Calls accept_paragraph_star with a RDoc::Markup::Paragraph containing + # bold words + + def test_accept_paragraph_star + @to.start_accepting + + @to.accept_paragraph @RM::Paragraph.new('reg *bold* reg') + + accept_paragraph_star + end + + ## + # Calls accept_paragraph_underscore with a RDoc::Markup::Paragraph + # containing emphasized words + + def test_accept_paragraph_underscore + @to.start_accepting + + @to.accept_paragraph @RM::Paragraph.new('reg _italic_ reg') + + accept_paragraph_underscore + end + + ## + # Calls accept_verbatim with a RDoc::Markup::Verbatim + + def test_accept_verbatim + @to.start_accepting + + @to.accept_verbatim @RM::Verbatim.new("hi\n", " world\n") + + accept_verbatim + end + + ## + # Calls accept_raw with a RDoc::Markup::Raw + + def test_accept_raw + @to.start_accepting + + @to.accept_raw @RM::Raw.new("<table>", + "<tr><th>Name<th>Count", + "<tr><td>a<td>1", + "<tr><td>b<td>2", + "</table>") + + accept_raw + end + + ## + # Calls accept_rule with a RDoc::Markup::Rule + + def test_accept_rule + @to.start_accepting + + @to.accept_rule @RM::Rule.new(4) + + accept_rule + end + + ## + # Calls accept_list_item_start_bullet + + def test_accept_list_item_start_bullet + @to.start_accepting + + @to.accept_list_start @bullet_list + + @to.accept_list_item_start @bullet_list.items.first + + accept_list_item_start_bullet + end + + ## + # Calls accept_list_item_start_label + + def test_accept_list_item_start_label + @to.start_accepting + + @to.accept_list_start @label_list + + @to.accept_list_item_start @label_list.items.first + + accept_list_item_start_label + end + + ## + # Calls accept_list_item_start_lalpha + + def test_accept_list_item_start_lalpha + @to.start_accepting + + @to.accept_list_start @lalpha_list + + @to.accept_list_item_start @lalpha_list.items.first + + accept_list_item_start_lalpha + end + + ## + # Calls accept_list_item_start_note + + def test_accept_list_item_start_note + @to.start_accepting + + @to.accept_list_start @note_list + + @to.accept_list_item_start @note_list.items.first + + accept_list_item_start_note + end + + ## + # Calls accept_list_item_start_note_2 + + def test_accept_list_item_start_note_2 + list = list(:NOTE, + item('<tt>teletype</tt>', + para('teletype description'))) + + @to.start_accepting + + list.accept @to + + @to.end_accepting + + accept_list_item_start_note_2 + end + + ## + # Calls accept_list_item_start_note_multi_description + + def test_accept_list_item_start_note_multi_description + list = list(:NOTE, + item(%w[label], + para('description one')), + item(nil, para('description two'))) + + @to.start_accepting + + list.accept @to + + @to.end_accepting + + accept_list_item_start_note_multi_description + end + + ## + # Calls accept_list_item_start_note_multi_label + + def test_accept_list_item_start_note_multi_label + list = list(:NOTE, + item(%w[one two], + para('two headers'))) + + @to.start_accepting + + list.accept @to + + @to.end_accepting + + accept_list_item_start_note_multi_label + end + + ## + # Calls accept_list_item_start_number + + def test_accept_list_item_start_number + @to.start_accepting + + @to.accept_list_start @number_list + + @to.accept_list_item_start @number_list.items.first + + accept_list_item_start_number + end + + ## + # Calls accept_list_item_start_ualpha + + def test_accept_list_item_start_ualpha + @to.start_accepting + + @to.accept_list_start @ualpha_list + + @to.accept_list_item_start @ualpha_list.items.first + + accept_list_item_start_ualpha + end + + ## + # Calls accept_list_item_end_bullet + + def test_accept_list_item_end_bullet + @to.start_accepting + + @to.accept_list_start @bullet_list + + @to.accept_list_item_start @bullet_list.items.first + + @to.accept_list_item_end @bullet_list.items.first + + accept_list_item_end_bullet + end + + ## + # Calls accept_list_item_end_label + + def test_accept_list_item_end_label + @to.start_accepting + + @to.accept_list_start @label_list + + @to.accept_list_item_start @label_list.items.first + + @to.accept_list_item_end @label_list.items.first + + accept_list_item_end_label + end + + ## + # Calls accept_list_item_end_lalpha + + def test_accept_list_item_end_lalpha + @to.start_accepting + + @to.accept_list_start @lalpha_list + + @to.accept_list_item_start @lalpha_list.items.first + + @to.accept_list_item_end @lalpha_list.items.first + + accept_list_item_end_lalpha + end + + ## + # Calls accept_list_item_end_note + + def test_accept_list_item_end_note + @to.start_accepting + + @to.accept_list_start @note_list + + @to.accept_list_item_start @note_list.items.first + + @to.accept_list_item_end @note_list.items.first + + accept_list_item_end_note + end + + ## + # Calls accept_list_item_end_number + + def test_accept_list_item_end_number + @to.start_accepting + + @to.accept_list_start @number_list + + @to.accept_list_item_start @number_list.items.first + + @to.accept_list_item_end @number_list.items.first + + accept_list_item_end_number + end + + ## + # Calls accept_list_item_end_ualpha + + def test_accept_list_item_end_ualpha + @to.start_accepting + + @to.accept_list_start @ualpha_list + + @to.accept_list_item_start @ualpha_list.items.first + + @to.accept_list_item_end @ualpha_list.items.first + + accept_list_item_end_ualpha + end + + ## + # Calls accept_list_start_bullet + + def test_accept_list_start_bullet + @to.start_accepting + + @to.accept_list_start @bullet_list + + accept_list_start_bullet + end + + ## + # Calls accept_list_start_label + + def test_accept_list_start_label + @to.start_accepting + + @to.accept_list_start @label_list + + accept_list_start_label + end + + ## + # Calls accept_list_start_lalpha + + def test_accept_list_start_lalpha + @to.start_accepting + + @to.accept_list_start @lalpha_list + + accept_list_start_lalpha + end + + ## + # Calls accept_list_start_note + + def test_accept_list_start_note + @to.start_accepting + + @to.accept_list_start @note_list + + accept_list_start_note + end + + ## + # Calls accept_list_start_number + + def test_accept_list_start_number + @to.start_accepting + + @to.accept_list_start @number_list + + accept_list_start_number + end + + ## + # Calls accept_list_start_ualpha + + def test_accept_list_start_ualpha + @to.start_accepting + + @to.accept_list_start @ualpha_list + + accept_list_start_ualpha + end + + ## + # Calls accept_list_end_bullet + + def test_accept_list_end_bullet + @to.start_accepting + + @to.accept_list_start @bullet_list + + @to.accept_list_end @bullet_list + + accept_list_end_bullet + end + + ## + # Calls accept_list_end_label + + def test_accept_list_end_label + @to.start_accepting + + @to.accept_list_start @label_list + + @to.accept_list_end @label_list + + accept_list_end_label + end + + ## + # Calls accept_list_end_lalpha + + def test_accept_list_end_lalpha + @to.start_accepting + + @to.accept_list_start @lalpha_list + + @to.accept_list_end @lalpha_list + + accept_list_end_lalpha + end + + ## + # Calls accept_list_end_number + + def test_accept_list_end_number + @to.start_accepting + + @to.accept_list_start @number_list + + @to.accept_list_end @number_list + + accept_list_end_number + end + + ## + # Calls accept_list_end_note + + def test_accept_list_end_note + @to.start_accepting + + @to.accept_list_start @note_list + + @to.accept_list_end @note_list + + accept_list_end_note + end + + ## + # Calls accept_list_end_ualpha + + def test_accept_list_end_ualpha + @to.start_accepting + + @to.accept_list_start @ualpha_list + + @to.accept_list_end @ualpha_list + + accept_list_end_ualpha + end + + ## + # Calls list_nested with a two-level list + + def test_list_nested + doc = @RM::Document.new( + @RM::List.new(:BULLET, + @RM::ListItem.new(nil, + @RM::Paragraph.new('l1'), + @RM::List.new(:BULLET, + @RM::ListItem.new(nil, + @RM::Paragraph.new('l1.1')))), + @RM::ListItem.new(nil, + @RM::Paragraph.new('l2')))) + + doc.accept @to + + list_nested + end + + ## + # Calls list_verbatim with a list containing a verbatim block + + def test_list_verbatim # HACK overblown + doc = + doc( + list(:BULLET, + item(nil, + para('list stuff'), + blank_line, + verb("* list\n", + " with\n", + "\n", + " second\n", + "\n", + " 1. indented\n", + " 2. numbered\n", + "\n", + " third\n", + "\n", + "* second\n")))) + + doc.accept @to + + list_verbatim + end + end + end + +end + diff --git a/jni/ruby/lib/rdoc/markup/hard_break.rb b/jni/ruby/lib/rdoc/markup/hard_break.rb new file mode 100644 index 0000000..8445ad2 --- /dev/null +++ b/jni/ruby/lib/rdoc/markup/hard_break.rb @@ -0,0 +1,31 @@ +## +# A hard-break in the middle of a paragraph. + +class RDoc::Markup::HardBreak + + @instance = new + + ## + # RDoc::Markup::HardBreak is a singleton + + def self.new + @instance + end + + ## + # Calls #accept_hard_break on +visitor+ + + def accept visitor + visitor.accept_hard_break self + end + + def == other # :nodoc: + self.class === other + end + + def pretty_print q # :nodoc: + q.text "[break]" + end + +end + diff --git a/jni/ruby/lib/rdoc/markup/heading.rb b/jni/ruby/lib/rdoc/markup/heading.rb new file mode 100644 index 0000000..535e310 --- /dev/null +++ b/jni/ruby/lib/rdoc/markup/heading.rb @@ -0,0 +1,78 @@ +## +# A heading with a level (1-6) and text + +RDoc::Markup::Heading = + Struct.new :level, :text do + + @to_html = nil + @to_label = nil + + ## + # A singleton RDoc::Markup::ToLabel formatter for headings. + + def self.to_label + @to_label ||= RDoc::Markup::ToLabel.new + end + + ## + # A singleton plain HTML formatter for headings. Used for creating labels + # for the Table of Contents + + def self.to_html + return @to_html if @to_html + + markup = RDoc::Markup.new + markup.add_special RDoc::CrossReference::CROSSREF_REGEXP, :CROSSREF + + @to_html = RDoc::Markup::ToHtml.new nil + + def @to_html.handle_special_CROSSREF special + special.text.sub(/^\\/, '') + end + + @to_html + end + + ## + # Calls #accept_heading on +visitor+ + + def accept visitor + visitor.accept_heading self + end + + ## + # An HTML-safe anchor reference for this header. + + def aref + "label-#{self.class.to_label.convert text.dup}" + end + + ## + # Creates a fully-qualified label which will include the label from + # +context+. This helps keep ids unique in HTML. + + def label context = nil + label = aref + + label = [context.aref, label].compact.join '-' if + context and context.respond_to? :aref + + label + end + + ## + # HTML markup of the text of this label without the surrounding header + # element. + + def plain_html + self.class.to_html.to_html(text.dup) + end + + def pretty_print q # :nodoc: + q.group 2, "[head: #{level} ", ']' do + q.pp text + end + end + +end + diff --git a/jni/ruby/lib/rdoc/markup/include.rb b/jni/ruby/lib/rdoc/markup/include.rb new file mode 100644 index 0000000..a2e8903 --- /dev/null +++ b/jni/ruby/lib/rdoc/markup/include.rb @@ -0,0 +1,42 @@ +## +# A file included at generation time. Objects of this class are created by +# RDoc::RD for an extension-less include. +# +# This implementation in incomplete. + +class RDoc::Markup::Include + + ## + # The filename to be included, without extension + + attr_reader :file + + ## + # Directories to search for #file + + attr_reader :include_path + + ## + # Creates a new include that will import +file+ from +include_path+ + + def initialize file, include_path + @file = file + @include_path = include_path + end + + def == other # :nodoc: + self.class === other and + @file == other.file and @include_path == other.include_path + end + + def pretty_print q # :nodoc: + q.group 2, '[incl ', ']' do + q.text file + q.breakable + q.text 'from ' + q.pp include_path + end + end + +end + diff --git a/jni/ruby/lib/rdoc/markup/indented_paragraph.rb b/jni/ruby/lib/rdoc/markup/indented_paragraph.rb new file mode 100644 index 0000000..1b8a8c7 --- /dev/null +++ b/jni/ruby/lib/rdoc/markup/indented_paragraph.rb @@ -0,0 +1,47 @@ +## +# An Indented Paragraph of text + +class RDoc::Markup::IndentedParagraph < RDoc::Markup::Raw + + ## + # The indent in number of spaces + + attr_reader :indent + + ## + # Creates a new IndentedParagraph containing +parts+ indented with +indent+ + # spaces + + def initialize indent, *parts + @indent = indent + + super(*parts) + end + + def == other # :nodoc: + super and indent == other.indent + end + + ## + # Calls #accept_indented_paragraph on +visitor+ + + def accept visitor + visitor.accept_indented_paragraph self + end + + ## + # Joins the raw paragraph text and converts inline HardBreaks to the + # +hard_break+ text followed by the indent. + + def text hard_break = nil + @parts.map do |part| + if RDoc::Markup::HardBreak === part then + '%1$s%3$*2$s' % [hard_break, @indent, ' '] if hard_break + else + part + end + end.join + end + +end + diff --git a/jni/ruby/lib/rdoc/markup/inline.rb b/jni/ruby/lib/rdoc/markup/inline.rb new file mode 100644 index 0000000..fb3ab5c --- /dev/null +++ b/jni/ruby/lib/rdoc/markup/inline.rb @@ -0,0 +1 @@ +warn "requiring rdoc/markup/inline is deprecated and will be removed in RDoc 4." if $-w diff --git a/jni/ruby/lib/rdoc/markup/list.rb b/jni/ruby/lib/rdoc/markup/list.rb new file mode 100644 index 0000000..89b7fc2 --- /dev/null +++ b/jni/ruby/lib/rdoc/markup/list.rb @@ -0,0 +1,101 @@ +## +# A List is a homogeneous set of ListItems. +# +# The supported list types include: +# +# :BULLET:: +# An unordered list +# :LABEL:: +# An unordered definition list, but using an alternate RDoc::Markup syntax +# :LALPHA:: +# An ordered list using increasing lowercase English letters +# :NOTE:: +# An unordered definition list +# :NUMBER:: +# An ordered list using increasing Arabic numerals +# :UALPHA:: +# An ordered list using increasing uppercase English letters +# +# Definition lists behave like HTML definition lists. Each list item can +# describe multiple terms. See RDoc::Markup::ListItem for how labels and +# definition are stored as list items. + +class RDoc::Markup::List + + ## + # The list's type + + attr_accessor :type + + ## + # Items in the list + + attr_reader :items + + ## + # Creates a new list of +type+ with +items+. Valid list types are: + # +:BULLET+, +:LABEL+, +:LALPHA+, +:NOTE+, +:NUMBER+, +:UALPHA+ + + def initialize type = nil, *items + @type = type + @items = [] + @items.concat items + end + + ## + # Appends +item+ to the list + + def << item + @items << item + end + + def == other # :nodoc: + self.class == other.class and + @type == other.type and + @items == other.items + end + + ## + # Runs this list and all its #items through +visitor+ + + def accept visitor + visitor.accept_list_start self + + @items.each do |item| + item.accept visitor + end + + visitor.accept_list_end self + end + + ## + # Is the list empty? + + def empty? + @items.empty? + end + + ## + # Returns the last item in the list + + def last + @items.last + end + + def pretty_print q # :nodoc: + q.group 2, "[list: #{@type} ", ']' do + q.seplist @items do |item| + q.pp item + end + end + end + + ## + # Appends +items+ to the list + + def push *items + @items.concat items + end + +end + diff --git a/jni/ruby/lib/rdoc/markup/list_item.rb b/jni/ruby/lib/rdoc/markup/list_item.rb new file mode 100644 index 0000000..c5e59fe --- /dev/null +++ b/jni/ruby/lib/rdoc/markup/list_item.rb @@ -0,0 +1,99 @@ +## +# An item within a List that contains paragraphs, headings, etc. +# +# For BULLET, NUMBER, LALPHA and UALPHA lists, the label will always be nil. +# For NOTE and LABEL lists, the list label may contain: +# +# * a single String for a single label +# * an Array of Strings for a list item with multiple terms +# * nil for an extra description attached to a previously labeled list item + +class RDoc::Markup::ListItem + + ## + # The label for the ListItem + + attr_accessor :label + + ## + # Parts of the ListItem + + attr_reader :parts + + ## + # Creates a new ListItem with an optional +label+ containing +parts+ + + def initialize label = nil, *parts + @label = label + @parts = [] + @parts.concat parts + end + + ## + # Appends +part+ to the ListItem + + def << part + @parts << part + end + + def == other # :nodoc: + self.class == other.class and + @label == other.label and + @parts == other.parts + end + + ## + # Runs this list item and all its #parts through +visitor+ + + def accept visitor + visitor.accept_list_item_start self + + @parts.each do |part| + part.accept visitor + end + + visitor.accept_list_item_end self + end + + ## + # Is the ListItem empty? + + def empty? + @parts.empty? + end + + ## + # Length of parts in the ListItem + + def length + @parts.length + end + + def pretty_print q # :nodoc: + q.group 2, '[item: ', ']' do + case @label + when Array then + q.pp @label + q.text ';' + q.breakable + when String then + q.pp @label + q.text ';' + q.breakable + end + + q.seplist @parts do |part| + q.pp part + end + end + end + + ## + # Adds +parts+ to the ListItem + + def push *parts + @parts.concat parts + end + +end + diff --git a/jni/ruby/lib/rdoc/markup/paragraph.rb b/jni/ruby/lib/rdoc/markup/paragraph.rb new file mode 100644 index 0000000..7180729 --- /dev/null +++ b/jni/ruby/lib/rdoc/markup/paragraph.rb @@ -0,0 +1,28 @@ +## +# A Paragraph of text + +class RDoc::Markup::Paragraph < RDoc::Markup::Raw + + ## + # Calls #accept_paragraph on +visitor+ + + def accept visitor + visitor.accept_paragraph self + end + + ## + # Joins the raw paragraph text and converts inline HardBreaks to the + # +hard_break+ text. + + def text hard_break = '' + @parts.map do |part| + if RDoc::Markup::HardBreak === part then + hard_break + else + part + end + end.join + end + +end + diff --git a/jni/ruby/lib/rdoc/markup/parser.rb b/jni/ruby/lib/rdoc/markup/parser.rb new file mode 100644 index 0000000..cc828a4 --- /dev/null +++ b/jni/ruby/lib/rdoc/markup/parser.rb @@ -0,0 +1,558 @@ +require 'strscan' + +## +# A recursive-descent parser for RDoc markup. +# +# The parser tokenizes an input string then parses the tokens into a Document. +# Documents can be converted into output formats by writing a visitor like +# RDoc::Markup::ToHTML. +# +# The parser only handles the block-level constructs Paragraph, List, +# ListItem, Heading, Verbatim, BlankLine and Rule. Inline markup such as +# <tt>\+blah\+</tt> is handled separately by RDoc::Markup::AttributeManager. +# +# To see what markup the Parser implements read RDoc. To see how to use +# RDoc markup to format text in your program read RDoc::Markup. + +class RDoc::Markup::Parser + + include RDoc::Text + + ## + # List token types + + LIST_TOKENS = [ + :BULLET, + :LABEL, + :LALPHA, + :NOTE, + :NUMBER, + :UALPHA, + ] + + ## + # Parser error subclass + + class Error < RuntimeError; end + + ## + # Raised when the parser is unable to handle the given markup + + class ParseError < Error; end + + ## + # Enables display of debugging information + + attr_accessor :debug + + ## + # Token accessor + + attr_reader :tokens + + ## + # Parses +str+ into a Document. + # + # Use RDoc::Markup#parse instead of this method. + + def self.parse str + parser = new + parser.tokenize str + doc = RDoc::Markup::Document.new + parser.parse doc + end + + ## + # Returns a token stream for +str+, for testing + + def self.tokenize str + parser = new + parser.tokenize str + parser.tokens + end + + ## + # Creates a new Parser. See also ::parse + + def initialize + @binary_input = nil + @current_token = nil + @debug = false + @have_encoding = Object.const_defined? :Encoding + @have_byteslice = ''.respond_to? :byteslice + @input = nil + @input_encoding = nil + @line = 0 + @line_pos = 0 + @s = nil + @tokens = [] + end + + ## + # Builds a Heading of +level+ + + def build_heading level + type, text, = get + + text = case type + when :TEXT then + skip :NEWLINE + text + else + unget + '' + end + + RDoc::Markup::Heading.new level, text + end + + ## + # Builds a List flush to +margin+ + + def build_list margin + p :list_start => margin if @debug + + list = RDoc::Markup::List.new + label = nil + + until @tokens.empty? do + type, data, column, = get + + case type + when *LIST_TOKENS then + if column < margin || (list.type && list.type != type) then + unget + break + end + + list.type = type + peek_type, _, column, = peek_token + + case type + when :NOTE, :LABEL then + label = [] unless label + + if peek_type == :NEWLINE then + # description not on the same line as LABEL/NOTE + # skip the trailing newline & any blank lines below + while peek_type == :NEWLINE + get + peek_type, _, column, = peek_token + end + + # we may be: + # - at end of stream + # - at a column < margin: + # [text] + # blah blah blah + # - at the same column, but with a different type of list item + # [text] + # * blah blah + # - at the same column, with the same type of list item + # [one] + # [two] + # In all cases, we have an empty description. + # In the last case only, we continue. + if peek_type.nil? || column < margin then + empty = true + elsif column == margin then + case peek_type + when type + empty = :continue + when *LIST_TOKENS + empty = true + else + empty = false + end + else + empty = false + end + + if empty then + label << data + next if empty == :continue + break + end + end + else + data = nil + end + + if label then + data = label << data + label = nil + end + + list_item = RDoc::Markup::ListItem.new data + parse list_item, column + list << list_item + + else + unget + break + end + end + + p :list_end => margin if @debug + + if list.empty? then + return nil unless label + return nil unless [:LABEL, :NOTE].include? list.type + + list_item = RDoc::Markup::ListItem.new label, RDoc::Markup::BlankLine.new + list << list_item + end + + list + end + + ## + # Builds a Paragraph that is flush to +margin+ + + def build_paragraph margin + p :paragraph_start => margin if @debug + + paragraph = RDoc::Markup::Paragraph.new + + until @tokens.empty? do + type, data, column, = get + + if type == :TEXT and column == margin then + paragraph << data + + break if peek_token.first == :BREAK + + data << ' ' if skip :NEWLINE + else + unget + break + end + end + + paragraph.parts.last.sub!(/ \z/, '') # cleanup + + p :paragraph_end => margin if @debug + + paragraph + end + + ## + # Builds a Verbatim that is indented from +margin+. + # + # The verbatim block is shifted left (the least indented lines start in + # column 0). Each part of the verbatim is one line of text, always + # terminated by a newline. Blank lines always consist of a single newline + # character, and there is never a single newline at the end of the verbatim. + + def build_verbatim margin + p :verbatim_begin => margin if @debug + verbatim = RDoc::Markup::Verbatim.new + + min_indent = nil + generate_leading_spaces = true + line = '' + + until @tokens.empty? do + type, data, column, = get + + if type == :NEWLINE then + line << data + verbatim << line + line = '' + generate_leading_spaces = true + next + end + + if column <= margin + unget + break + end + + if generate_leading_spaces then + indent = column - margin + line << ' ' * indent + min_indent = indent if min_indent.nil? || indent < min_indent + generate_leading_spaces = false + end + + case type + when :HEADER then + line << '=' * data + _, _, peek_column, = peek_token + peek_column ||= column + data + indent = peek_column - column - data + line << ' ' * indent + when :RULE then + width = 2 + data + line << '-' * width + _, _, peek_column, = peek_token + peek_column ||= column + width + indent = peek_column - column - width + line << ' ' * indent + when :BREAK, :TEXT then + line << data + else # *LIST_TOKENS + list_marker = case type + when :BULLET then data + when :LABEL then "[#{data}]" + when :NOTE then "#{data}::" + else # :LALPHA, :NUMBER, :UALPHA + "#{data}." + end + line << list_marker + peek_type, _, peek_column = peek_token + unless peek_type == :NEWLINE then + peek_column ||= column + list_marker.length + indent = peek_column - column - list_marker.length + line << ' ' * indent + end + end + + end + + verbatim << line << "\n" unless line.empty? + verbatim.parts.each { |p| p.slice!(0, min_indent) unless p == "\n" } if min_indent > 0 + verbatim.normalize + + p :verbatim_end => margin if @debug + + verbatim + end + + ## + # The character offset for the input string at the given +byte_offset+ + + def char_pos byte_offset + if @have_byteslice then + @input.byteslice(0, byte_offset).length + elsif @have_encoding then + matched = @binary_input[0, byte_offset] + matched.force_encoding @input_encoding + matched.length + else + byte_offset + end + end + + ## + # Pulls the next token from the stream. + + def get + @current_token = @tokens.shift + p :get => @current_token if @debug + @current_token + end + + ## + # Parses the tokens into an array of RDoc::Markup::XXX objects, + # and appends them to the passed +parent+ RDoc::Markup::YYY object. + # + # Exits at the end of the token stream, or when it encounters a token + # in a column less than +indent+ (unless it is a NEWLINE). + # + # Returns +parent+. + + def parse parent, indent = 0 + p :parse_start => indent if @debug + + until @tokens.empty? do + type, data, column, = get + + case type + when :BREAK then + parent << RDoc::Markup::BlankLine.new + skip :NEWLINE, false + next + when :NEWLINE then + # trailing newlines are skipped below, so this is a blank line + parent << RDoc::Markup::BlankLine.new + skip :NEWLINE, false + next + end + + # indentation change: break or verbatim + if column < indent then + unget + break + elsif column > indent then + unget + parent << build_verbatim(indent) + next + end + + # indentation is the same + case type + when :HEADER then + parent << build_heading(data) + when :RULE then + parent << RDoc::Markup::Rule.new(data) + skip :NEWLINE + when :TEXT then + unget + parse_text parent, indent + when *LIST_TOKENS then + unget + parent << build_list(indent) + else + type, data, column, line = @current_token + raise ParseError, "Unhandled token #{type} (#{data.inspect}) at #{line}:#{column}" + end + end + + p :parse_end => indent if @debug + + parent + + end + + ## + # Small hook that is overridden by RDoc::TomDoc + + def parse_text parent, indent # :nodoc: + parent << build_paragraph(indent) + end + + ## + # Returns the next token on the stream without modifying the stream + + def peek_token + token = @tokens.first || [] + p :peek => token if @debug + token + end + + ## + # Creates the StringScanner + + def setup_scanner input + @line = 0 + @line_pos = 0 + @input = input.dup + + if @have_encoding and not @have_byteslice then + @input_encoding = @input.encoding + @binary_input = @input.force_encoding Encoding::BINARY + end + + @s = StringScanner.new input + end + + ## + # Skips the next token if its type is +token_type+. + # + # Optionally raises an error if the next token is not of the expected type. + + def skip token_type, error = true + type, = get + return unless type # end of stream + return @current_token if token_type == type + unget + raise ParseError, "expected #{token_type} got #{@current_token.inspect}" if error + end + + ## + # Turns text +input+ into a stream of tokens + + def tokenize input + setup_scanner input + + until @s.eos? do + pos = @s.pos + + # leading spaces will be reflected by the column of the next token + # the only thing we loose are trailing spaces at the end of the file + next if @s.scan(/ +/) + + # note: after BULLET, LABEL, etc., + # indent will be the column of the next non-newline token + + @tokens << case + # [CR]LF => :NEWLINE + when @s.scan(/\r?\n/) then + token = [:NEWLINE, @s.matched, *token_pos(pos)] + @line_pos = char_pos @s.pos + @line += 1 + token + # === text => :HEADER then :TEXT + when @s.scan(/(=+)(\s*)/) then + level = @s[1].length + header = [:HEADER, level, *token_pos(pos)] + + if @s[2] =~ /^\r?\n/ then + @s.pos -= @s[2].length + header + else + pos = @s.pos + @s.scan(/.*/) + @tokens << header + [:TEXT, @s.matched.sub(/\r$/, ''), *token_pos(pos)] + end + # --- (at least 3) and nothing else on the line => :RULE + when @s.scan(/(-{3,}) *\r?$/) then + [:RULE, @s[1].length - 2, *token_pos(pos)] + # * or - followed by white space and text => :BULLET + when @s.scan(/([*-]) +(\S)/) then + @s.pos -= @s[2].bytesize # unget \S + [:BULLET, @s[1], *token_pos(pos)] + # A. text, a. text, 12. text => :UALPHA, :LALPHA, :NUMBER + when @s.scan(/([a-z]|\d+)\. +(\S)/i) then + # FIXME if tab(s), the column will be wrong + # either support tabs everywhere by first expanding them to + # spaces, or assume that they will have been replaced + # before (and provide a check for that at least in debug + # mode) + list_label = @s[1] + @s.pos -= @s[2].bytesize # unget \S + list_type = + case list_label + when /[a-z]/ then :LALPHA + when /[A-Z]/ then :UALPHA + when /\d/ then :NUMBER + else + raise ParseError, "BUG token #{list_label}" + end + [list_type, list_label, *token_pos(pos)] + # [text] followed by spaces or end of line => :LABEL + when @s.scan(/\[(.*?)\]( +|\r?$)/) then + [:LABEL, @s[1], *token_pos(pos)] + # text:: followed by spaces or end of line => :NOTE + when @s.scan(/(.*?)::( +|\r?$)/) then + [:NOTE, @s[1], *token_pos(pos)] + # anything else: :TEXT + else @s.scan(/(.*?)( )?\r?$/) + token = [:TEXT, @s[1], *token_pos(pos)] + + if @s[2] then + @tokens << token + [:BREAK, @s[2], *token_pos(pos + @s[1].length)] + else + token + end + end + end + + self + end + + ## + # Calculates the column (by character) and line of the current token based + # on +byte_offset+. + + def token_pos byte_offset + offset = char_pos byte_offset + + [offset - @line_pos, @line] + end + + ## + # Returns the current token to the token stream + + def unget + token = @current_token + p :unget => token if @debug + raise Error, 'too many #ungets' if token == @tokens.first + @tokens.unshift token if token + end + +end + diff --git a/jni/ruby/lib/rdoc/markup/pre_process.rb b/jni/ruby/lib/rdoc/markup/pre_process.rb new file mode 100644 index 0000000..01fb293 --- /dev/null +++ b/jni/ruby/lib/rdoc/markup/pre_process.rb @@ -0,0 +1,293 @@ +## +# Handle common directives that can occur in a block of text: +# +# \:include: filename +# +# Directives can be escaped by preceding them with a backslash. +# +# RDoc plugin authors can register additional directives to be handled by +# using RDoc::Markup::PreProcess::register. +# +# Any directive that is not built-in to RDoc (including those registered via +# plugins) will be stored in the metadata hash on the CodeObject the comment +# is attached to. See RDoc::Markup@Directives for the list of built-in +# directives. + +class RDoc::Markup::PreProcess + + ## + # An RDoc::Options instance that will be filled in with overrides from + # directives + + attr_accessor :options + + ## + # Adds a post-process handler for directives. The handler will be called + # with the result RDoc::Comment (or text String) and the code object for the + # comment (if any). + + def self.post_process &block + @post_processors << block + end + + ## + # Registered post-processors + + def self.post_processors + @post_processors + end + + ## + # Registers +directive+ as one handled by RDoc. If a block is given the + # directive will be replaced by the result of the block, otherwise the + # directive will be removed from the processed text. + # + # The block will be called with the directive name and the directive + # parameter: + # + # RDoc::Markup::PreProcess.register 'my-directive' do |directive, param| + # # replace text, etc. + # end + + def self.register directive, &block + @registered[directive] = block + end + + ## + # Registered directives + + def self.registered + @registered + end + + ## + # Clears all registered directives and post-processors + + def self.reset + @post_processors = [] + @registered = {} + end + + reset + + ## + # Creates a new pre-processor for +input_file_name+ that will look for + # included files in +include_path+ + + def initialize(input_file_name, include_path) + @input_file_name = input_file_name + @include_path = include_path + @options = nil + end + + ## + # Look for directives in the given +text+. + # + # Options that we don't handle are yielded. If the block returns false the + # directive is restored to the text. If the block returns nil or no block + # was given the directive is handled according to the registered directives. + # If a String was returned the directive is replaced with the string. + # + # If no matching directive was registered the directive is restored to the + # text. + # + # If +code_object+ is given and the directive is unknown then the + # directive's parameter is set as metadata on the +code_object+. See + # RDoc::CodeObject#metadata for details. + + def handle text, code_object = nil, &block + if RDoc::Comment === text then + comment = text + text = text.text + end + + encoding = text.encoding if defined?(Encoding) + + # regexp helper (square brackets for optional) + # $1 $2 $3 $4 $5 + # [prefix][\]:directive:[spaces][param]newline + text.gsub!(/^([ \t]*(?:#|\/?\*)?[ \t]*)(\\?):(\w+):([ \t]*)(.+)?(\r?\n|$)/) do + # skip something like ':toto::' + next $& if $4.empty? and $5 and $5[0, 1] == ':' + + # skip if escaped + next "#$1:#$3:#$4#$5\n" unless $2.empty? + + # This is not in handle_directive because I didn't want to pass another + # argument into it + if comment and $3 == 'markup' then + next "#{$1.strip}\n" unless $5 + comment.format = $5.downcase + next "#{$1.strip}\n" + end + + handle_directive $1, $3, $5, code_object, encoding, &block + end + + comment = text unless comment + + self.class.post_processors.each do |handler| + handler.call comment, code_object + end + + text + end + + ## + # Performs the actions described by +directive+ and its parameter +param+. + # + # +code_object+ is used for directives that operate on a class or module. + # +prefix+ is used to ensure the replacement for handled directives is + # correct. +encoding+ is used for the <tt>include</tt> directive. + # + # For a list of directives in RDoc see RDoc::Markup. + #-- + # When 1.8.7 support is ditched prefix can be defaulted to '' + + def handle_directive prefix, directive, param, code_object = nil, + encoding = nil + blankline = "#{prefix.strip}\n" + directive = directive.downcase + + case directive + when 'arg', 'args' then + return "#{prefix}:#{directive}: #{param}\n" unless code_object + + code_object.params = param + + blankline + when 'category' then + if RDoc::Context === code_object then + section = code_object.add_section param + code_object.temporary_section = section + end + + blankline # ignore category if we're not on an RDoc::Context + when 'doc' then + return blankline unless code_object + code_object.document_self = true + code_object.force_documentation = true + + blankline + when 'enddoc' then + return blankline unless code_object + code_object.done_documenting = true + + blankline + when 'include' then + filename = param.split.first + include_file filename, prefix, encoding + when 'main' then + @options.main_page = param if @options.respond_to? :main_page + + blankline + when 'nodoc' then + return blankline unless code_object + code_object.document_self = nil # notify nodoc + code_object.document_children = param !~ /all/i + + blankline + when 'notnew', 'not_new', 'not-new' then + return blankline unless RDoc::AnyMethod === code_object + + code_object.dont_rename_initialize = true + + blankline + when 'startdoc' then + return blankline unless code_object + + code_object.start_doc + code_object.force_documentation = true + + blankline + when 'stopdoc' then + return blankline unless code_object + + code_object.stop_doc + + blankline + when 'title' then + @options.default_title = param if @options.respond_to? :default_title= + + blankline + when 'yield', 'yields' then + return blankline unless code_object + # remove parameter &block + code_object.params.sub!(/,?\s*&\w+/, '') if code_object.params + + code_object.block_params = param + + blankline + else + result = yield directive, param if block_given? + + case result + when nil then + code_object.metadata[directive] = param if code_object + + if RDoc::Markup::PreProcess.registered.include? directive then + handler = RDoc::Markup::PreProcess.registered[directive] + result = handler.call directive, param if handler + else + result = "#{prefix}:#{directive}: #{param}\n" + end + when false then + result = "#{prefix}:#{directive}: #{param}\n" + end + + result + end + end + + ## + # Handles the <tt>:include: _filename_</tt> directive. + # + # If the first line of the included file starts with '#', and contains + # an encoding information in the form 'coding:' or 'coding=', it is + # removed. + # + # If all lines in the included file start with a '#', this leading '#' + # is removed before inclusion. The included content is indented like + # the <tt>:include:</tt> directive. + #-- + # so all content will be verbatim because of the likely space after '#'? + # TODO shift left the whole file content in that case + # TODO comment stop/start #-- and #++ in included file must be processed here + + def include_file name, indent, encoding + full_name = find_include_file name + + unless full_name then + warn "Couldn't find file to include '#{name}' from #{@input_file_name}" + return '' + end + + content = RDoc::Encoding.read_file full_name, encoding, true + + # strip magic comment + content = content.sub(/\A# .*coding[=:].*$/, '').lstrip + + # strip leading '#'s, but only if all lines start with them + if content =~ /^[^#]/ then + content.gsub(/^/, indent) + else + content.gsub(/^#?/, indent) + end + end + + ## + # Look for the given file in the directory containing the current file, + # and then in each of the directories specified in the RDOC_INCLUDE path + + def find_include_file(name) + to_search = [File.dirname(@input_file_name)].concat @include_path + to_search.each do |dir| + full_name = File.join(dir, name) + stat = File.stat(full_name) rescue next + return full_name if stat.readable? + end + nil + end + +end + diff --git a/jni/ruby/lib/rdoc/markup/raw.rb b/jni/ruby/lib/rdoc/markup/raw.rb new file mode 100644 index 0000000..e11e8ef --- /dev/null +++ b/jni/ruby/lib/rdoc/markup/raw.rb @@ -0,0 +1,69 @@ +## +# A section of text that is added to the output document as-is + +class RDoc::Markup::Raw + + ## + # The component parts of the list + + attr_reader :parts + + ## + # Creates a new Raw containing +parts+ + + def initialize *parts + @parts = [] + @parts.concat parts + end + + ## + # Appends +text+ + + def << text + @parts << text + end + + def == other # :nodoc: + self.class == other.class and @parts == other.parts + end + + ## + # Calls #accept_raw+ on +visitor+ + + def accept visitor + visitor.accept_raw self + end + + ## + # Appends +other+'s parts + + def merge other + @parts.concat other.parts + end + + def pretty_print q # :nodoc: + self.class.name =~ /.*::(\w{1,4})/i + + q.group 2, "[#{$1.downcase}: ", ']' do + q.seplist @parts do |part| + q.pp part + end + end + end + + ## + # Appends +texts+ onto this Paragraph + + def push *texts + self.parts.concat texts + end + + ## + # The raw text + + def text + @parts.join ' ' + end + +end + diff --git a/jni/ruby/lib/rdoc/markup/rule.rb b/jni/ruby/lib/rdoc/markup/rule.rb new file mode 100644 index 0000000..b778f2b --- /dev/null +++ b/jni/ruby/lib/rdoc/markup/rule.rb @@ -0,0 +1,20 @@ +## +# A horizontal rule with a weight + +class RDoc::Markup::Rule < Struct.new :weight + + ## + # Calls #accept_rule on +visitor+ + + def accept visitor + visitor.accept_rule self + end + + def pretty_print q # :nodoc: + q.group 2, '[rule:', ']' do + q.pp weight + end + end + +end + diff --git a/jni/ruby/lib/rdoc/markup/special.rb b/jni/ruby/lib/rdoc/markup/special.rb new file mode 100644 index 0000000..1c0fc03 --- /dev/null +++ b/jni/ruby/lib/rdoc/markup/special.rb @@ -0,0 +1,40 @@ +## +# Hold details of a special sequence + +class RDoc::Markup::Special + + ## + # Special type + + attr_reader :type + + ## + # Special text + + attr_accessor :text + + ## + # Creates a new special sequence of +type+ with +text+ + + def initialize(type, text) + @type, @text = type, text + end + + ## + # Specials are equal when the have the same text and type + + def ==(o) + self.text == o.text && self.type == o.type + end + + def inspect # :nodoc: + "#<RDoc::Markup::Special:0x%x @type=%p, @text=%p>" % [ + object_id, @type, text.dump] + end + + def to_s # :nodoc: + "Special: type=#{type} text=#{text.dump}" + end + +end + diff --git a/jni/ruby/lib/rdoc/markup/text_formatter_test_case.rb b/jni/ruby/lib/rdoc/markup/text_formatter_test_case.rb new file mode 100644 index 0000000..4abf425 --- /dev/null +++ b/jni/ruby/lib/rdoc/markup/text_formatter_test_case.rb @@ -0,0 +1,114 @@ +## +# Test case for creating new plain-text RDoc::Markup formatters. See also +# RDoc::Markup::FormatterTestCase +# +# See test_rdoc_markup_to_rdoc.rb for a complete example. +# +# Example: +# +# class TestRDocMarkupToNewTextFormat < RDoc::Markup::TextFormatterTestCase +# +# add_visitor_tests +# add_text_tests +# +# def setup +# super +# +# @to = RDoc::Markup::ToNewTextFormat.new +# end +# +# def accept_blank_line +# assert_equal :junk, @to.res.join +# end +# +# # ... +# +# end + +class RDoc::Markup::TextFormatterTestCase < RDoc::Markup::FormatterTestCase + + ## + # Adds test cases to the calling TestCase. + + def self.add_text_tests + self.class_eval do + + ## + # Test case that calls <tt>@to.accept_heading</tt> + + def test_accept_heading_indent + @to.start_accepting + @to.indent = 3 + @to.accept_heading @RM::Heading.new(1, 'Hello') + + accept_heading_indent + end + + ## + # Test case that calls <tt>@to.accept_rule</tt> + + def test_accept_rule_indent + @to.start_accepting + @to.indent = 3 + @to.accept_rule @RM::Rule.new(1) + + accept_rule_indent + end + + ## + # Test case that calls <tt>@to.accept_verbatim</tt> + + def test_accept_verbatim_indent + @to.start_accepting + @to.indent = 2 + @to.accept_verbatim @RM::Verbatim.new("hi\n", " world\n") + + accept_verbatim_indent + end + + ## + # Test case that calls <tt>@to.accept_verbatim</tt> with a big indent + + def test_accept_verbatim_big_indent + @to.start_accepting + @to.indent = 2 + @to.accept_verbatim @RM::Verbatim.new("hi\n", "world\n") + + accept_verbatim_big_indent + end + + ## + # Test case that calls <tt>@to.accept_paragraph</tt> with an indent + + def test_accept_paragraph_indent + @to.start_accepting + @to.indent = 3 + @to.accept_paragraph @RM::Paragraph.new(('words ' * 30).strip) + + accept_paragraph_indent + end + + ## + # Test case that calls <tt>@to.accept_paragraph</tt> with a long line + + def test_accept_paragraph_wrap + @to.start_accepting + @to.accept_paragraph @RM::Paragraph.new(('words ' * 30).strip) + + accept_paragraph_wrap + end + + ## + # Test case that calls <tt>@to.attributes</tt> with an escaped + # cross-reference. If this test doesn't pass something may be very + # wrong. + + def test_attributes + assert_equal 'Dog', @to.attributes("\\Dog") + end + + end + end + +end + diff --git a/jni/ruby/lib/rdoc/markup/to_ansi.rb b/jni/ruby/lib/rdoc/markup/to_ansi.rb new file mode 100644 index 0000000..4d439ce --- /dev/null +++ b/jni/ruby/lib/rdoc/markup/to_ansi.rb @@ -0,0 +1,93 @@ +## +# Outputs RDoc markup with vibrant ANSI color! + +class RDoc::Markup::ToAnsi < RDoc::Markup::ToRdoc + + ## + # Creates a new ToAnsi visitor that is ready to output vibrant ANSI color! + + def initialize markup = nil + super + + @headings.clear + @headings[1] = ["\e[1;32m", "\e[m"] # bold + @headings[2] = ["\e[4;32m", "\e[m"] # underline + @headings[3] = ["\e[32m", "\e[m"] # just green + end + + ## + # Maps attributes to ANSI sequences + + def init_tags + add_tag :BOLD, "\e[1m", "\e[m" + add_tag :TT, "\e[7m", "\e[m" + add_tag :EM, "\e[4m", "\e[m" + end + + ## + # Overrides indent width to ensure output lines up correctly. + + def accept_list_item_end list_item + width = case @list_type.last + when :BULLET then + 2 + when :NOTE, :LABEL then + if @prefix then + @res << @prefix.strip + @prefix = nil + end + + @res << "\n" unless res.length == 1 + 2 + else + bullet = @list_index.last.to_s + @list_index[-1] = @list_index.last.succ + bullet.length + 2 + end + + @indent -= width + end + + ## + # Adds coloring to note and label list items + + def accept_list_item_start list_item + bullet = case @list_type.last + when :BULLET then + '*' + when :NOTE, :LABEL then + labels = Array(list_item.label).map do |label| + attributes(label).strip + end.join "\n" + + labels << ":\n" unless labels.empty? + + labels + else + @list_index.last.to_s + '.' + end + + case @list_type.last + when :NOTE, :LABEL then + @indent += 2 + @prefix = bullet + (' ' * @indent) + else + @prefix = (' ' * @indent) + bullet.ljust(bullet.length + 1) + + width = bullet.gsub(/\e\[[\d;]*m/, '').length + 1 + + @indent += width + end + end + + ## + # Starts accepting with a reset screen + + def start_accepting + super + + @res = ["\e[0m"] + end + +end + diff --git a/jni/ruby/lib/rdoc/markup/to_bs.rb b/jni/ruby/lib/rdoc/markup/to_bs.rb new file mode 100644 index 0000000..10c3185 --- /dev/null +++ b/jni/ruby/lib/rdoc/markup/to_bs.rb @@ -0,0 +1,78 @@ +## +# Outputs RDoc markup with hot backspace action! You will probably need a +# pager to use this output format. +# +# This formatter won't work on 1.8.6 because it lacks String#chars. + +class RDoc::Markup::ToBs < RDoc::Markup::ToRdoc + + ## + # Returns a new ToBs that is ready for hot backspace action! + + def initialize markup = nil + super + + @in_b = false + @in_em = false + end + + ## + # Sets a flag that is picked up by #annotate to do the right thing in + # #convert_string + + def init_tags + add_tag :BOLD, '+b', '-b' + add_tag :EM, '+_', '-_' + add_tag :TT, '' , '' # we need in_tt information maintained + end + + ## + # Makes heading text bold. + + def accept_heading heading + use_prefix or @res << ' ' * @indent + @res << @headings[heading.level][0] + @in_b = true + @res << attributes(heading.text) + @in_b = false + @res << @headings[heading.level][1] + @res << "\n" + end + + ## + # Turns on or off special handling for +convert_string+ + + def annotate tag + case tag + when '+b' then @in_b = true + when '-b' then @in_b = false + when '+_' then @in_em = true + when '-_' then @in_em = false + end + '' + end + + ## + # Calls convert_string on the result of convert_special + + def convert_special special + convert_string super + end + + ## + # Adds bold or underline mixed with backspaces + + def convert_string string + return string unless string.respond_to? :chars # your ruby is lame + return string unless @in_b or @in_em + chars = if @in_b then + string.chars.map do |char| "#{char}\b#{char}" end + elsif @in_em then + string.chars.map do |char| "_\b#{char}" end + end + + chars.join + end + +end + diff --git a/jni/ruby/lib/rdoc/markup/to_html.rb b/jni/ruby/lib/rdoc/markup/to_html.rb new file mode 100644 index 0000000..2b1216e --- /dev/null +++ b/jni/ruby/lib/rdoc/markup/to_html.rb @@ -0,0 +1,398 @@ +require 'cgi' + +## +# Outputs RDoc markup as HTML. + +class RDoc::Markup::ToHtml < RDoc::Markup::Formatter + + include RDoc::Text + + # :section: Utilities + + ## + # Maps RDoc::Markup::Parser::LIST_TOKENS types to HTML tags + + LIST_TYPE_TO_HTML = { + :BULLET => ['<ul>', '</ul>'], + :LABEL => ['<dl class="rdoc-list label-list">', '</dl>'], + :LALPHA => ['<ol style="list-style-type: lower-alpha">', '</ol>'], + :NOTE => ['<dl class="rdoc-list note-list">', '</dl>'], + :NUMBER => ['<ol>', '</ol>'], + :UALPHA => ['<ol style="list-style-type: upper-alpha">', '</ol>'], + } + + attr_reader :res # :nodoc: + attr_reader :in_list_entry # :nodoc: + attr_reader :list # :nodoc: + + ## + # The RDoc::CodeObject HTML is being generated for. This is used to + # generate namespaced URI fragments + + attr_accessor :code_object + + ## + # Path to this document for relative links + + attr_accessor :from_path + + # :section: + + ## + # Creates a new formatter that will output HTML + + def initialize options, markup = nil + super + + @code_object = nil + @from_path = '' + @in_list_entry = nil + @list = nil + @th = nil + @hard_break = "<br>\n" + + # external links + @markup.add_special(/(?:link:|https?:|mailto:|ftp:|irc:|www\.)\S+\w/, + :HYPERLINK) + + add_special_RDOCLINK + add_special_TIDYLINK + + init_tags + end + + # :section: Special Handling + # + # These methods handle special markup added by RDoc::Markup#add_special. + + def handle_RDOCLINK url # :nodoc: + case url + when /^rdoc-ref:/ + $' + when /^rdoc-label:/ + text = $' + + text = case text + when /\Alabel-/ then $' + when /\Afootmark-/ then $' + when /\Afoottext-/ then $' + else text + end + + gen_url url, text + when /^rdoc-image:/ + "<img src=\"#{$'}\">" + else + url =~ /\Ardoc-[a-z]+:/ + + $' + end + end + + ## + # +special+ is a <code><br></code> + + def handle_special_HARD_BREAK special + '<br>' + end + + ## + # +special+ is a potential link. The following schemes are handled: + # + # <tt>mailto:</tt>:: + # Inserted as-is. + # <tt>http:</tt>:: + # Links are checked to see if they reference an image. If so, that image + # gets inserted using an <tt><img></tt> tag. Otherwise a conventional + # <tt><a href></tt> is used. + # <tt>link:</tt>:: + # Reference to a local file relative to the output directory. + + def handle_special_HYPERLINK(special) + url = special.text + + gen_url url, url + end + + ## + # +special+ is an rdoc-schemed link that will be converted into a hyperlink. + # + # For the +rdoc-ref+ scheme the named reference will be returned without + # creating a link. + # + # For the +rdoc-label+ scheme the footnote and label prefixes are stripped + # when creating a link. All other contents will be linked verbatim. + + def handle_special_RDOCLINK special + handle_RDOCLINK special.text + end + + ## + # This +special+ is a link where the label is different from the URL + # <tt>label[url]</tt> or <tt>{long label}[url]</tt> + + def handle_special_TIDYLINK(special) + text = special.text + + return text unless + text =~ /^\{(.*)\}\[(.*?)\]$/ or text =~ /^(\S+)\[(.*?)\]$/ + + label = $1 + url = $2 + + label = handle_RDOCLINK label if /^rdoc-image:/ =~ label + + gen_url url, label + end + + # :section: Visitor + # + # These methods implement the HTML visitor. + + ## + # Prepares the visitor for HTML generation + + def start_accepting + @res = [] + @in_list_entry = [] + @list = [] + end + + ## + # Returns the generated output + + def end_accepting + @res.join + end + + ## + # Adds +block_quote+ to the output + + def accept_block_quote block_quote + @res << "\n<blockquote>" + + block_quote.parts.each do |part| + part.accept self + end + + @res << "</blockquote>\n" + end + + ## + # Adds +paragraph+ to the output + + def accept_paragraph paragraph + @res << "\n<p>" + text = paragraph.text @hard_break + text = text.gsub(/\r?\n/, ' ') + @res << wrap(to_html(text)) + @res << "</p>\n" + end + + ## + # Adds +verbatim+ to the output + + def accept_verbatim verbatim + text = verbatim.text.rstrip + + klass = nil + + content = if verbatim.ruby? or parseable? text then + begin + tokens = RDoc::RubyLex.tokenize text, @options + klass = ' class="ruby"' + + RDoc::TokenStream.to_html tokens + rescue RDoc::RubyLex::Error + CGI.escapeHTML text + end + else + CGI.escapeHTML text + end + + if @options.pipe then + @res << "\n<pre><code>#{CGI.escapeHTML text}</code></pre>\n" + else + @res << "\n<pre#{klass}>#{content}</pre>\n" + end + end + + ## + # Adds +rule+ to the output + + def accept_rule rule + @res << "<hr>\n" + end + + ## + # Prepares the visitor for consuming +list+ + + def accept_list_start(list) + @list << list.type + @res << html_list_name(list.type, true) + @in_list_entry.push false + end + + ## + # Finishes consumption of +list+ + + def accept_list_end(list) + @list.pop + if tag = @in_list_entry.pop + @res << tag + end + @res << html_list_name(list.type, false) << "\n" + end + + ## + # Prepares the visitor for consuming +list_item+ + + def accept_list_item_start(list_item) + if tag = @in_list_entry.last + @res << tag + end + + @res << list_item_start(list_item, @list.last) + end + + ## + # Finishes consumption of +list_item+ + + def accept_list_item_end(list_item) + @in_list_entry[-1] = list_end_for(@list.last) + end + + ## + # Adds +blank_line+ to the output + + def accept_blank_line(blank_line) + # @res << annotate("<p />") << "\n" + end + + ## + # Adds +heading+ to the output. The headings greater than 6 are trimmed to + # level 6. + + def accept_heading heading + level = [6, heading.level].min + + label = heading.label @code_object + + @res << if @options.output_decoration + "\n<h#{level} id=\"#{label}\">" + else + "\n<h#{level}>" + end + @res << to_html(heading.text) + unless @options.pipe then + @res << "<span><a href=\"##{label}\">¶</a>" + @res << " <a href=\"#top\">↑</a></span>" + end + @res << "</h#{level}>\n" + end + + ## + # Adds +raw+ to the output + + def accept_raw raw + @res << raw.parts.join("\n") + end + + # :section: Utilities + + ## + # CGI-escapes +text+ + + def convert_string(text) + CGI.escapeHTML text + end + + ## + # Generate a link to +url+ with content +text+. Handles the special cases + # for img: and link: described under handle_special_HYPERLINK + + def gen_url url, text + scheme, url, id = parse_url url + + if %w[http https link].include?(scheme) and + url =~ /\.(gif|png|jpg|jpeg|bmp)$/ then + "<img src=\"#{url}\" />" + else + text = text.sub %r%^#{scheme}:/*%i, '' + text = text.sub %r%^[*\^](\d+)$%, '\1' + + link = "<a#{id} href=\"#{url}\">#{text}</a>" + + link = "<sup>#{link}</sup>" if /"foot/ =~ id + + link + end + end + + ## + # Determines the HTML list element for +list_type+ and +open_tag+ + + def html_list_name(list_type, open_tag) + tags = LIST_TYPE_TO_HTML[list_type] + raise RDoc::Error, "Invalid list type: #{list_type.inspect}" unless tags + tags[open_tag ? 0 : 1] + end + + ## + # Maps attributes to HTML tags + + def init_tags + add_tag :BOLD, "<strong>", "</strong>" + add_tag :TT, "<code>", "</code>" + add_tag :EM, "<em>", "</em>" + end + + ## + # Returns the HTML tag for +list_type+, possible using a label from + # +list_item+ + + def list_item_start(list_item, list_type) + case list_type + when :BULLET, :LALPHA, :NUMBER, :UALPHA then + "<li>" + when :LABEL, :NOTE then + Array(list_item.label).map do |label| + "<dt>#{to_html label}\n" + end.join << "<dd>" + else + raise RDoc::Error, "Invalid list type: #{list_type.inspect}" + end + end + + ## + # Returns the HTML end-tag for +list_type+ + + def list_end_for(list_type) + case list_type + when :BULLET, :LALPHA, :NUMBER, :UALPHA then + "</li>" + when :LABEL, :NOTE then + "</dd>" + else + raise RDoc::Error, "Invalid list type: #{list_type.inspect}" + end + end + + ## + # Returns true if text is valid ruby syntax + + def parseable? text + eval("BEGIN {return true}\n#{text}") + rescue SyntaxError + false + end + + ## + # Converts +item+ to HTML using RDoc::Text#to_html + + def to_html item + super convert_flow @am.flow item + end + +end + diff --git a/jni/ruby/lib/rdoc/markup/to_html_crossref.rb b/jni/ruby/lib/rdoc/markup/to_html_crossref.rb new file mode 100644 index 0000000..d27e0ab --- /dev/null +++ b/jni/ruby/lib/rdoc/markup/to_html_crossref.rb @@ -0,0 +1,160 @@ +## +# Subclass of the RDoc::Markup::ToHtml class that supports looking up method +# names, classes, etc to create links. RDoc::CrossReference is used to +# generate those links based on the current context. + +class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml + + # :stopdoc: + ALL_CROSSREF_REGEXP = RDoc::CrossReference::ALL_CROSSREF_REGEXP + CLASS_REGEXP_STR = RDoc::CrossReference::CLASS_REGEXP_STR + CROSSREF_REGEXP = RDoc::CrossReference::CROSSREF_REGEXP + METHOD_REGEXP_STR = RDoc::CrossReference::METHOD_REGEXP_STR + # :startdoc: + + ## + # RDoc::CodeObject for generating references + + attr_accessor :context + + ## + # Should we show '#' characters on method references? + + attr_accessor :show_hash + + ## + # Creates a new crossref resolver that generates links relative to +context+ + # which lives at +from_path+ in the generated files. '#' characters on + # references are removed unless +show_hash+ is true. Only method names + # preceded by '#' or '::' are linked, unless +hyperlink_all+ is true. + + def initialize(options, from_path, context, markup = nil) + raise ArgumentError, 'from_path cannot be nil' if from_path.nil? + + super options, markup + + @context = context + @from_path = from_path + @hyperlink_all = @options.hyperlink_all + @show_hash = @options.show_hash + + crossref_re = @hyperlink_all ? ALL_CROSSREF_REGEXP : CROSSREF_REGEXP + @markup.add_special crossref_re, :CROSSREF + + @cross_reference = RDoc::CrossReference.new @context + end + + ## + # Creates a link to the reference +name+ if the name exists. If +text+ is + # given it is used as the link text, otherwise +name+ is used. + + def cross_reference name, text = nil + lookup = name + + name = name[1..-1] unless @show_hash if name[0, 1] == '#' + + name = "#{CGI.unescape $'} at #{$1}" if name =~ /(.*[^#:])@/ + + text = name unless text + + link lookup, text + end + + ## + # We're invoked when any text matches the CROSSREF pattern. If we find the + # corresponding reference, generate a link. If the name we're looking for + # contains no punctuation, we look for it up the module/class chain. For + # example, ToHtml is found, even without the <tt>RDoc::Markup::</tt> prefix, + # because we look for it in module Markup first. + + def handle_special_CROSSREF(special) + name = special.text + + return name if name =~ /@[\w-]+\.[\w-]/ # labels that look like emails + + unless @hyperlink_all then + # This ensures that words entirely consisting of lowercase letters will + # not have cross-references generated (to suppress lots of erroneous + # cross-references to "new" in text, for instance) + return name if name =~ /\A[a-z]*\z/ + end + + cross_reference name + end + + ## + # Handles <tt>rdoc-ref:</tt> scheme links and allows RDoc::Markup::ToHtml to + # handle other schemes. + + def handle_special_HYPERLINK special + return cross_reference $' if special.text =~ /\Ardoc-ref:/ + + super + end + + ## + # +special+ is an rdoc-schemed link that will be converted into a hyperlink. + # For the rdoc-ref scheme the cross-reference will be looked up and the + # given name will be used. + # + # All other contents are handled by + # {the superclass}[rdoc-ref:RDoc::Markup::ToHtml#handle_special_RDOCLINK] + + def handle_special_RDOCLINK special + url = special.text + + case url + when /\Ardoc-ref:/ then + cross_reference $' + else + super + end + end + + ## + # Generates links for <tt>rdoc-ref:</tt> scheme URLs and allows + # RDoc::Markup::ToHtml to handle other schemes. + + def gen_url url, text + return super unless url =~ /\Ardoc-ref:/ + + cross_reference $', text + end + + ## + # Creates an HTML link to +name+ with the given +text+. + + def link name, text + original_name = name + + if name =~ /(.*[^#:])@/ then + name = $1 + label = $' + end + + ref = @cross_reference.resolve name, text + + text = ref.output_name @context if + RDoc::MethodAttr === ref and text == original_name + + case ref + when String then + ref + else + path = ref.as_href @from_path + + if path =~ /#/ then + path << "-label-#{label}" + elsif ref.sections and + ref.sections.any? { |section| label == section.title } then + path << "##{label}" + else + path << "#label-#{label}" + end if label + + "<a href=\"#{path}\">#{text}</a>" + end + end + +end + diff --git a/jni/ruby/lib/rdoc/markup/to_html_snippet.rb b/jni/ruby/lib/rdoc/markup/to_html_snippet.rb new file mode 100644 index 0000000..4ad0a9a --- /dev/null +++ b/jni/ruby/lib/rdoc/markup/to_html_snippet.rb @@ -0,0 +1,284 @@ +## +# Outputs RDoc markup as paragraphs with inline markup only. + +class RDoc::Markup::ToHtmlSnippet < RDoc::Markup::ToHtml + + ## + # After this many characters the input will be cut off. + + attr_reader :character_limit + + ## + # The number of characters seen so far. + + attr_reader :characters # :nodoc: + + ## + # The attribute bitmask + + attr_reader :mask + + ## + # After this many paragraphs the input will be cut off. + + attr_reader :paragraph_limit + + ## + # Count of paragraphs found + + attr_reader :paragraphs + + ## + # Creates a new ToHtmlSnippet formatter that will cut off the input on the + # next word boundary after the given number of +characters+ or +paragraphs+ + # of text have been encountered. + + def initialize options, characters = 100, paragraphs = 3, markup = nil + super options, markup + + @character_limit = characters + @paragraph_limit = paragraphs + + @characters = 0 + @mask = 0 + @paragraphs = 0 + + @markup.add_special RDoc::CrossReference::CROSSREF_REGEXP, :CROSSREF + end + + ## + # Adds +heading+ to the output as a paragraph + + def accept_heading heading + @res << "<p>#{to_html heading.text}\n" + + add_paragraph + end + + ## + # Raw sections are untrusted and ignored + + alias accept_raw ignore + + ## + # Rules are ignored + + alias accept_rule ignore + + def accept_paragraph paragraph + para = @in_list_entry.last || "<p>" + + text = paragraph.text @hard_break + + @res << "#{para}#{wrap to_html text}\n" + + add_paragraph + end + + ## + # Finishes consumption of +list_item+ + + def accept_list_item_end list_item + end + + ## + # Prepares the visitor for consuming +list_item+ + + def accept_list_item_start list_item + @res << list_item_start(list_item, @list.last) + end + + ## + # Prepares the visitor for consuming +list+ + + def accept_list_start list + @list << list.type + @res << html_list_name(list.type, true) + @in_list_entry.push '' + end + + ## + # Adds +verbatim+ to the output + + def accept_verbatim verbatim + throw :done if @characters >= @character_limit + input = verbatim.text.rstrip + + text = truncate input + text << ' ...' unless text == input + + super RDoc::Markup::Verbatim.new text + + add_paragraph + end + + ## + # Prepares the visitor for HTML snippet generation + + def start_accepting + super + + @characters = 0 + end + + ## + # Removes escaping from the cross-references in +special+ + + def handle_special_CROSSREF special + special.text.sub(/\A\\/, '') + end + + ## + # +special+ is a <code><br></code> + + def handle_special_HARD_BREAK special + @characters -= 4 + '<br>' + end + + ## + # Lists are paragraphs, but notes and labels have a separator + + def list_item_start list_item, list_type + throw :done if @characters >= @character_limit + + case list_type + when :BULLET, :LALPHA, :NUMBER, :UALPHA then + "<p>" + when :LABEL, :NOTE then + labels = Array(list_item.label).map do |label| + to_html label + end.join ', ' + + labels << " — " unless labels.empty? + + start = "<p>#{labels}" + @characters += 1 # try to include the label + start + else + raise RDoc::Error, "Invalid list type: #{list_type.inspect}" + end + end + + ## + # Returns just the text of +link+, +url+ is only used to determine the link + # type. + + def gen_url url, text + if url =~ /^rdoc-label:([^:]*)(?::(.*))?/ then + type = "link" + elsif url =~ /([A-Za-z]+):(.*)/ then + type = $1 + else + type = "http" + end + + if (type == "http" or type == "https" or type == "link") and + url =~ /\.(gif|png|jpg|jpeg|bmp)$/ then + '' + else + text.sub(%r%^#{type}:/*%, '') + end + end + + ## + # In snippets, there are no lists + + def html_list_name list_type, open_tag + '' + end + + ## + # Throws +:done+ when paragraph_limit paragraphs have been encountered + + def add_paragraph + @paragraphs += 1 + + throw :done if @paragraphs >= @paragraph_limit + end + + ## + # Marks up +content+ + + def convert content + catch :done do + return super + end + + end_accepting + end + + ## + # Converts flow items +flow+ + + def convert_flow flow + throw :done if @characters >= @character_limit + + res = [] + @mask = 0 + + flow.each do |item| + case item + when RDoc::Markup::AttrChanger then + off_tags res, item + on_tags res, item + when String then + text = convert_string item + res << truncate(text) + when RDoc::Markup::Special then + text = convert_special item + res << truncate(text) + else + raise "Unknown flow element: #{item.inspect}" + end + + if @characters >= @character_limit then + off_tags res, RDoc::Markup::AttrChanger.new(0, @mask) + break + end + end + + res << ' ...' if @characters >= @character_limit + + res.join + end + + ## + # Maintains a bitmask to allow HTML elements to be closed properly. See + # RDoc::Markup::Formatter. + + def on_tags res, item + @mask ^= item.turn_on + + super + end + + ## + # Maintains a bitmask to allow HTML elements to be closed properly. See + # RDoc::Markup::Formatter. + + def off_tags res, item + @mask ^= item.turn_off + + super + end + + ## + # Truncates +text+ at the end of the first word after the character_limit. + + def truncate text + length = text.length + characters = @characters + @characters += length + + return text if @characters < @character_limit + + remaining = @character_limit - characters + + text =~ /\A(.{#{remaining},}?)(\s|$)/m # TODO word-break instead of \s? + + $1 + end + +end + diff --git a/jni/ruby/lib/rdoc/markup/to_joined_paragraph.rb b/jni/ruby/lib/rdoc/markup/to_joined_paragraph.rb new file mode 100644 index 0000000..8358410 --- /dev/null +++ b/jni/ruby/lib/rdoc/markup/to_joined_paragraph.rb @@ -0,0 +1,71 @@ +## +# Joins the parts of an RDoc::Markup::Paragraph into a single String. +# +# This allows for easier maintenance and testing of Markdown support. +# +# This formatter only works on Paragraph instances. Attempting to process +# other markup syntax items will not work. + +class RDoc::Markup::ToJoinedParagraph < RDoc::Markup::Formatter + + def initialize # :nodoc: + super nil + end + + def start_accepting # :nodoc: + end + + def end_accepting # :nodoc: + end + + ## + # Converts the parts of +paragraph+ to a single entry. + + def accept_paragraph paragraph + parts = [] + string = false + + paragraph.parts.each do |part| + if String === part then + if string then + string << part + else + parts << part + string = part + end + else + parts << part + string = false + end + end + + parts = parts.map do |part| + if String === part then + part.rstrip + else + part + end + end + + # TODO use Enumerable#chunk when Ruby 1.8 support is dropped + #parts = paragraph.parts.chunk do |part| + # String === part + #end.map do |string, chunk| + # string ? chunk.join.rstrip : chunk + #end.flatten + + paragraph.parts.replace parts + end + + alias accept_block_quote ignore + alias accept_heading ignore + alias accept_list_end ignore + alias accept_list_item_end ignore + alias accept_list_item_start ignore + alias accept_list_start ignore + alias accept_raw ignore + alias accept_rule ignore + alias accept_verbatim ignore + +end + diff --git a/jni/ruby/lib/rdoc/markup/to_label.rb b/jni/ruby/lib/rdoc/markup/to_label.rb new file mode 100644 index 0000000..6fbe4a3 --- /dev/null +++ b/jni/ruby/lib/rdoc/markup/to_label.rb @@ -0,0 +1,74 @@ +require 'cgi' + +## +# Creates HTML-safe labels suitable for use in id attributes. Tidylinks are +# converted to their link part and cross-reference links have the suppression +# marks removed (\\SomeClass is converted to SomeClass). + +class RDoc::Markup::ToLabel < RDoc::Markup::Formatter + + attr_reader :res # :nodoc: + + ## + # Creates a new formatter that will output HTML-safe labels + + def initialize markup = nil + super nil, markup + + @markup.add_special RDoc::CrossReference::CROSSREF_REGEXP, :CROSSREF + @markup.add_special(/(((\{.*?\})|\b\S+?)\[\S+?\])/, :TIDYLINK) + + add_tag :BOLD, '', '' + add_tag :TT, '', '' + add_tag :EM, '', '' + + @res = [] + end + + ## + # Converts +text+ to an HTML-safe label + + def convert text + label = convert_flow @am.flow text + + CGI.escape(label).gsub('%', '-').sub(/^-/, '') + end + + ## + # Converts the CROSSREF +special+ to plain text, removing the suppression + # marker, if any + + def handle_special_CROSSREF special + text = special.text + + text.sub(/^\\/, '') + end + + ## + # Converts the TIDYLINK +special+ to just the text part + + def handle_special_TIDYLINK special + text = special.text + + return text unless text =~ /\{(.*?)\}\[(.*?)\]/ or text =~ /(\S+)\[(.*?)\]/ + + $1 + end + + alias accept_blank_line ignore + alias accept_block_quote ignore + alias accept_heading ignore + alias accept_list_end ignore + alias accept_list_item_end ignore + alias accept_list_item_start ignore + alias accept_list_start ignore + alias accept_paragraph ignore + alias accept_raw ignore + alias accept_rule ignore + alias accept_verbatim ignore + alias end_accepting ignore + alias handle_special_HARD_BREAK ignore + alias start_accepting ignore + +end + diff --git a/jni/ruby/lib/rdoc/markup/to_markdown.rb b/jni/ruby/lib/rdoc/markup/to_markdown.rb new file mode 100644 index 0000000..d4b15bf --- /dev/null +++ b/jni/ruby/lib/rdoc/markup/to_markdown.rb @@ -0,0 +1,191 @@ +# :markup: markdown + +## +# Outputs parsed markup as Markdown + +class RDoc::Markup::ToMarkdown < RDoc::Markup::ToRdoc + + ## + # Creates a new formatter that will output Markdown format text + + def initialize markup = nil + super + + @headings[1] = ['# ', ''] + @headings[2] = ['## ', ''] + @headings[3] = ['### ', ''] + @headings[4] = ['#### ', ''] + @headings[5] = ['##### ', ''] + @headings[6] = ['###### ', ''] + + add_special_RDOCLINK + add_special_TIDYLINK + + @hard_break = " \n" + end + + ## + # Maps attributes to HTML sequences + + def init_tags + add_tag :BOLD, '**', '**' + add_tag :EM, '*', '*' + add_tag :TT, '`', '`' + end + + ## + # Adds a newline to the output + + def handle_special_HARD_BREAK special + " \n" + end + + ## + # Finishes consumption of `list` + + def accept_list_end list + @res << "\n" + + super + end + + ## + # Finishes consumption of `list_item` + + def accept_list_item_end list_item + width = case @list_type.last + when :BULLET then + 4 + when :NOTE, :LABEL then + use_prefix + + 4 + else + @list_index[-1] = @list_index.last.succ + 4 + end + + @indent -= width + end + + ## + # Prepares the visitor for consuming `list_item` + + def accept_list_item_start list_item + type = @list_type.last + + case type + when :NOTE, :LABEL then + bullets = Array(list_item.label).map do |label| + attributes(label).strip + end.join "\n" + + bullets << "\n:" + + @prefix = ' ' * @indent + @indent += 4 + @prefix << bullets + (' ' * (@indent - 1)) + else + bullet = type == :BULLET ? '*' : @list_index.last.to_s + '.' + @prefix = (' ' * @indent) + bullet.ljust(4) + + @indent += 4 + end + end + + ## + # Prepares the visitor for consuming `list` + + def accept_list_start list + case list.type + when :BULLET, :LABEL, :NOTE then + @list_index << nil + when :LALPHA, :NUMBER, :UALPHA then + @list_index << 1 + else + raise RDoc::Error, "invalid list type #{list.type}" + end + + @list_width << 4 + @list_type << list.type + end + + ## + # Adds `rule` to the output + + def accept_rule rule + use_prefix or @res << ' ' * @indent + @res << '-' * 3 + @res << "\n" + end + + ## + # Outputs `verbatim` indented 4 columns + + def accept_verbatim verbatim + indent = ' ' * (@indent + 4) + + verbatim.parts.each do |part| + @res << indent unless part == "\n" + @res << part + end + + @res << "\n" unless @res =~ /\n\z/ + end + + ## + # Creates a Markdown-style URL from +url+ with +text+. + + def gen_url url, text + scheme, url, = parse_url url + + "[#{text.sub(%r{^#{scheme}:/*}i, '')}](#{url})" + end + + ## + # Handles <tt>rdoc-</tt> type links for footnotes. + + def handle_rdoc_link url + case url + when /^rdoc-ref:/ then + $' + when /^rdoc-label:footmark-(\d+)/ then + "[^#{$1}]:" + when /^rdoc-label:foottext-(\d+)/ then + "[^#{$1}]" + when /^rdoc-label:label-/ then + gen_url url, $' + when /^rdoc-image:/ then + "![](#{$'})" + when /^rdoc-[a-z]+:/ then + $' + end + end + + ## + # Converts the RDoc markup tidylink into a Markdown.style link. + + def handle_special_TIDYLINK special + text = special.text + + return text unless text =~ /\{(.*?)\}\[(.*?)\]/ or text =~ /(\S+)\[(.*?)\]/ + + label = $1 + url = $2 + + if url =~ /^rdoc-label:foot/ then + handle_rdoc_link url + else + gen_url url, label + end + end + + ## + # Converts the rdoc-...: links into a Markdown.style links. + + def handle_special_RDOCLINK special + handle_rdoc_link special.text + end + +end + diff --git a/jni/ruby/lib/rdoc/markup/to_rdoc.rb b/jni/ruby/lib/rdoc/markup/to_rdoc.rb new file mode 100644 index 0000000..f16b4ed --- /dev/null +++ b/jni/ruby/lib/rdoc/markup/to_rdoc.rb @@ -0,0 +1,333 @@ +## +# Outputs RDoc markup as RDoc markup! (mostly) + +class RDoc::Markup::ToRdoc < RDoc::Markup::Formatter + + ## + # Current indent amount for output in characters + + attr_accessor :indent + + ## + # Output width in characters + + attr_accessor :width + + ## + # Stack of current list indexes for alphabetic and numeric lists + + attr_reader :list_index + + ## + # Stack of list types + + attr_reader :list_type + + ## + # Stack of list widths for indentation + + attr_reader :list_width + + ## + # Prefix for the next list item. See #use_prefix + + attr_reader :prefix + + ## + # Output accumulator + + attr_reader :res + + ## + # Creates a new formatter that will output (mostly) \RDoc markup + + def initialize markup = nil + super nil, markup + + @markup.add_special(/\\\S/, :SUPPRESSED_CROSSREF) + @width = 78 + init_tags + + @headings = {} + @headings.default = [] + + @headings[1] = ['= ', ''] + @headings[2] = ['== ', ''] + @headings[3] = ['=== ', ''] + @headings[4] = ['==== ', ''] + @headings[5] = ['===== ', ''] + @headings[6] = ['====== ', ''] + + @hard_break = "\n" + end + + ## + # Maps attributes to HTML sequences + + def init_tags + add_tag :BOLD, "<b>", "</b>" + add_tag :TT, "<tt>", "</tt>" + add_tag :EM, "<em>", "</em>" + end + + ## + # Adds +blank_line+ to the output + + def accept_blank_line blank_line + @res << "\n" + end + + ## + # Adds +paragraph+ to the output + + def accept_block_quote block_quote + @indent += 2 + + block_quote.parts.each do |part| + @prefix = '> ' + + part.accept self + end + + @indent -= 2 + end + + ## + # Adds +heading+ to the output + + def accept_heading heading + use_prefix or @res << ' ' * @indent + @res << @headings[heading.level][0] + @res << attributes(heading.text) + @res << @headings[heading.level][1] + @res << "\n" + end + + ## + # Finishes consumption of +list+ + + def accept_list_end list + @list_index.pop + @list_type.pop + @list_width.pop + end + + ## + # Finishes consumption of +list_item+ + + def accept_list_item_end list_item + width = case @list_type.last + when :BULLET then + 2 + when :NOTE, :LABEL then + if @prefix then + @res << @prefix.strip + @prefix = nil + end + + @res << "\n" + 2 + else + bullet = @list_index.last.to_s + @list_index[-1] = @list_index.last.succ + bullet.length + 2 + end + + @indent -= width + end + + ## + # Prepares the visitor for consuming +list_item+ + + def accept_list_item_start list_item + type = @list_type.last + + case type + when :NOTE, :LABEL then + bullets = Array(list_item.label).map do |label| + attributes(label).strip + end.join "\n" + + bullets << ":\n" unless bullets.empty? + + @prefix = ' ' * @indent + @indent += 2 + @prefix << bullets + (' ' * @indent) + else + bullet = type == :BULLET ? '*' : @list_index.last.to_s + '.' + @prefix = (' ' * @indent) + bullet.ljust(bullet.length + 1) + width = bullet.length + 1 + @indent += width + end + end + + ## + # Prepares the visitor for consuming +list+ + + def accept_list_start list + case list.type + when :BULLET then + @list_index << nil + @list_width << 1 + when :LABEL, :NOTE then + @list_index << nil + @list_width << 2 + when :LALPHA then + @list_index << 'a' + @list_width << list.items.length.to_s.length + when :NUMBER then + @list_index << 1 + @list_width << list.items.length.to_s.length + when :UALPHA then + @list_index << 'A' + @list_width << list.items.length.to_s.length + else + raise RDoc::Error, "invalid list type #{list.type}" + end + + @list_type << list.type + end + + ## + # Adds +paragraph+ to the output + + def accept_paragraph paragraph + text = paragraph.text @hard_break + wrap attributes text + end + + ## + # Adds +paragraph+ to the output + + def accept_indented_paragraph paragraph + @indent += paragraph.indent + text = paragraph.text @hard_break + wrap attributes text + @indent -= paragraph.indent + end + + ## + # Adds +raw+ to the output + + def accept_raw raw + @res << raw.parts.join("\n") + end + + ## + # Adds +rule+ to the output + + def accept_rule rule + use_prefix or @res << ' ' * @indent + @res << '-' * (@width - @indent) + @res << "\n" + end + + ## + # Outputs +verbatim+ indented 2 columns + + def accept_verbatim verbatim + indent = ' ' * (@indent + 2) + + verbatim.parts.each do |part| + @res << indent unless part == "\n" + @res << part + end + + @res << "\n" unless @res =~ /\n\z/ + end + + ## + # Applies attribute-specific markup to +text+ using RDoc::AttributeManager + + def attributes text + flow = @am.flow text.dup + convert_flow flow + end + + ## + # Returns the generated output + + def end_accepting + @res.join + end + + ## + # Removes preceding \\ from the suppressed crossref +special+ + + def handle_special_SUPPRESSED_CROSSREF special + text = special.text + text = text.sub('\\', '') unless in_tt? + text + end + + ## + # Adds a newline to the output + + def handle_special_HARD_BREAK special + "\n" + end + + ## + # Prepares the visitor for text generation + + def start_accepting + @res = [""] + @indent = 0 + @prefix = nil + + @list_index = [] + @list_type = [] + @list_width = [] + end + + ## + # Adds the stored #prefix to the output and clears it. Lists generate a + # prefix for later consumption. + + def use_prefix + prefix, @prefix = @prefix, nil + @res << prefix if prefix + + prefix + end + + ## + # Wraps +text+ to #width + + def wrap text + return unless text && !text.empty? + + text_len = @width - @indent + + text_len = 20 if text_len < 20 + + re = /^(.{0,#{text_len}})[ \n]/ + next_prefix = ' ' * @indent + + prefix = @prefix || next_prefix + @prefix = nil + + @res << prefix + + while text.length > text_len + if text =~ re then + @res << $1 + text.slice!(0, $&.length) + else + @res << text.slice!(0, text_len) + end + + @res << "\n" << next_prefix + end + + if text.empty? then + @res.pop + @res.pop + else + @res << text + @res << "\n" + end + end + +end + diff --git a/jni/ruby/lib/rdoc/markup/to_table_of_contents.rb b/jni/ruby/lib/rdoc/markup/to_table_of_contents.rb new file mode 100644 index 0000000..2e0f98c --- /dev/null +++ b/jni/ruby/lib/rdoc/markup/to_table_of_contents.rb @@ -0,0 +1,87 @@ +## +# Extracts just the RDoc::Markup::Heading elements from a +# RDoc::Markup::Document to help build a table of contents + +class RDoc::Markup::ToTableOfContents < RDoc::Markup::Formatter + + @to_toc = nil + + ## + # Singleton for table-of-contents generation + + def self.to_toc + @to_toc ||= new + end + + ## + # Output accumulator + + attr_reader :res + + ## + # Omits headings with a level less than the given level. + + attr_accessor :omit_headings_below + + def initialize # :nodoc: + super nil + + @omit_headings_below = nil + end + + ## + # Adds +document+ to the output, using its heading cutoff if present + + def accept_document document + @omit_headings_below = document.omit_headings_below + + super + end + + ## + # Adds +heading+ to the table of contents + + def accept_heading heading + @res << heading unless suppressed? heading + end + + ## + # Returns the table of contents + + def end_accepting + @res + end + + ## + # Prepares the visitor for text generation + + def start_accepting + @omit_headings_below = nil + @res = [] + end + + ## + # Returns true if +heading+ is below the display threshold + + def suppressed? heading + return false unless @omit_headings_below + + heading.level > @omit_headings_below + end + + # :stopdoc: + alias accept_block_quote ignore + alias accept_raw ignore + alias accept_rule ignore + alias accept_blank_line ignore + alias accept_paragraph ignore + alias accept_verbatim ignore + alias accept_list_end ignore + alias accept_list_item_start ignore + alias accept_list_item_end ignore + alias accept_list_end_bullet ignore + alias accept_list_start ignore + # :startdoc: + +end + diff --git a/jni/ruby/lib/rdoc/markup/to_test.rb b/jni/ruby/lib/rdoc/markup/to_test.rb new file mode 100644 index 0000000..c51f64b --- /dev/null +++ b/jni/ruby/lib/rdoc/markup/to_test.rb @@ -0,0 +1,69 @@ +## +# This Markup outputter is used for testing purposes. + +class RDoc::Markup::ToTest < RDoc::Markup::Formatter + + # :stopdoc: + + ## + # :section: Visitor + + def start_accepting + @res = [] + @list = [] + end + + def end_accepting + @res + end + + def accept_paragraph(paragraph) + @res << convert_flow(@am.flow(paragraph.text)) + end + + def accept_raw raw + @res << raw.parts.join + end + + def accept_verbatim(verbatim) + @res << verbatim.text.gsub(/^(\S)/, ' \1') + end + + def accept_list_start(list) + @list << case list.type + when :BULLET then + '*' + when :NUMBER then + '1' + else + list.type + end + end + + def accept_list_end(list) + @list.pop + end + + def accept_list_item_start(list_item) + @res << "#{' ' * (@list.size - 1)}#{@list.last}: " + end + + def accept_list_item_end(list_item) + end + + def accept_blank_line(blank_line) + @res << "\n" + end + + def accept_heading(heading) + @res << "#{'=' * heading.level} #{heading.text}" + end + + def accept_rule(rule) + @res << '-' * rule.weight + end + + # :startdoc: + +end + diff --git a/jni/ruby/lib/rdoc/markup/to_tt_only.rb b/jni/ruby/lib/rdoc/markup/to_tt_only.rb new file mode 100644 index 0000000..e2da20c --- /dev/null +++ b/jni/ruby/lib/rdoc/markup/to_tt_only.rb @@ -0,0 +1,120 @@ +## +# Extracts sections of text enclosed in plus, tt or code. Used to discover +# undocumented parameters. + +class RDoc::Markup::ToTtOnly < RDoc::Markup::Formatter + + ## + # Stack of list types + + attr_reader :list_type + + ## + # Output accumulator + + attr_reader :res + + ## + # Creates a new tt-only formatter. + + def initialize markup = nil + super nil, markup + + add_tag :TT, nil, nil + end + + ## + # Adds tts from +block_quote+ to the output + + def accept_block_quote block_quote + tt_sections block_quote.text + end + + ## + # Pops the list type for +list+ from #list_type + + def accept_list_end list + @list_type.pop + end + + ## + # Pushes the list type for +list+ onto #list_type + + def accept_list_start list + @list_type << list.type + end + + ## + # Prepares the visitor for consuming +list_item+ + + def accept_list_item_start list_item + case @list_type.last + when :NOTE, :LABEL then + Array(list_item.label).map do |label| + tt_sections label + end.flatten + end + end + + ## + # Adds +paragraph+ to the output + + def accept_paragraph paragraph + tt_sections(paragraph.text) + end + + ## + # Does nothing to +markup_item+ because it doesn't have any user-built + # content + + def do_nothing markup_item + end + + alias accept_blank_line do_nothing # :nodoc: + alias accept_heading do_nothing # :nodoc: + alias accept_list_item_end do_nothing # :nodoc: + alias accept_raw do_nothing # :nodoc: + alias accept_rule do_nothing # :nodoc: + alias accept_verbatim do_nothing # :nodoc: + + ## + # Extracts tt sections from +text+ + + def tt_sections text + flow = @am.flow text.dup + + flow.each do |item| + case item + when String then + @res << item if in_tt? + when RDoc::Markup::AttrChanger then + off_tags res, item + on_tags res, item + when RDoc::Markup::Special then + @res << convert_special(item) if in_tt? # TODO can this happen? + else + raise "Unknown flow element: #{item.inspect}" + end + end + + res + end + + ## + # Returns an Array of items that were wrapped in plus, tt or code. + + def end_accepting + @res.compact + end + + ## + # Prepares the visitor for gathering tt sections + + def start_accepting + @res = [] + + @list_type = [] + end + +end + diff --git a/jni/ruby/lib/rdoc/markup/verbatim.rb b/jni/ruby/lib/rdoc/markup/verbatim.rb new file mode 100644 index 0000000..0ddde67 --- /dev/null +++ b/jni/ruby/lib/rdoc/markup/verbatim.rb @@ -0,0 +1,83 @@ +## +# A section of verbatim text + +class RDoc::Markup::Verbatim < RDoc::Markup::Raw + + ## + # Format of this verbatim section + + attr_accessor :format + + def initialize *parts # :nodoc: + super + + @format = nil + end + + def == other # :nodoc: + super and @format == other.format + end + + ## + # Calls #accept_verbatim on +visitor+ + + def accept visitor + visitor.accept_verbatim self + end + + ## + # Collapses 3+ newlines into two newlines + + def normalize + parts = [] + + newlines = 0 + + @parts.each do |part| + case part + when /^\s*\n/ then + newlines += 1 + parts << part if newlines == 1 + else + newlines = 0 + parts << part + end + end + + parts.pop if parts.last =~ /\A\r?\n\z/ + + @parts = parts + end + + def pretty_print q # :nodoc: + self.class.name =~ /.*::(\w{1,4})/i + + q.group 2, "[#{$1.downcase}: ", ']' do + if @format then + q.text "format: #{@format}" + q.breakable + end + + q.seplist @parts do |part| + q.pp part + end + end + end + + ## + # Is this verbatim section Ruby code? + + def ruby? + @format ||= nil # TODO for older ri data, switch the tree to marshal_dump + @format == :ruby + end + + ## + # The text of the section + + def text + @parts.join + end + +end + diff --git a/jni/ruby/lib/rdoc/meta_method.rb b/jni/ruby/lib/rdoc/meta_method.rb new file mode 100644 index 0000000..68ba810 --- /dev/null +++ b/jni/ruby/lib/rdoc/meta_method.rb @@ -0,0 +1,6 @@ +## +# MetaMethod represents a meta-programmed method + +class RDoc::MetaMethod < RDoc::AnyMethod +end + diff --git a/jni/ruby/lib/rdoc/method_attr.rb b/jni/ruby/lib/rdoc/method_attr.rb new file mode 100644 index 0000000..a0ea851 --- /dev/null +++ b/jni/ruby/lib/rdoc/method_attr.rb @@ -0,0 +1,418 @@ +## +# Abstract class representing either a method or an attribute. + +class RDoc::MethodAttr < RDoc::CodeObject + + include Comparable + + ## + # Name of this method/attribute. + + attr_accessor :name + + ## + # public, protected, private + + attr_accessor :visibility + + ## + # Is this a singleton method/attribute? + + attr_accessor :singleton + + ## + # Source file token stream + + attr_reader :text + + ## + # Array of other names for this method/attribute + + attr_reader :aliases + + ## + # The method/attribute we're aliasing + + attr_accessor :is_alias_for + + #-- + # The attributes below are for AnyMethod only. + # They are left here for the time being to + # allow ri to operate. + # TODO modify ri to avoid calling these on attributes. + #++ + + ## + # Parameters yielded by the called block + + attr_reader :block_params + + ## + # Parameters for this method + + attr_accessor :params + + ## + # Different ways to call this method + + attr_accessor :call_seq + + ## + # The call_seq or the param_seq with method name, if there is no call_seq. + + attr_reader :arglists + + ## + # Pretty parameter list for this method + + attr_reader :param_seq + + + ## + # Creates a new MethodAttr from token stream +text+ and method or attribute + # name +name+. + # + # Usually this is called by super from a subclass. + + def initialize text, name + super() + + @text = text + @name = name + + @aliases = [] + @is_alias_for = nil + @parent_name = nil + @singleton = nil + @visibility = :public + @see = false + + @arglists = nil + @block_params = nil + @call_seq = nil + @param_seq = nil + @params = nil + end + + ## + # Resets cached data for the object so it can be rebuilt by accessor methods + + def initialize_copy other # :nodoc: + @full_name = nil + end + + def initialize_visibility # :nodoc: + super + @see = nil + end + + ## + # Order by #singleton then #name + + def <=>(other) + return unless other.respond_to?(:singleton) && + other.respond_to?(:name) + + [ @singleton ? 0 : 1, name] <=> + [other.singleton ? 0 : 1, other.name] + end + + def == other # :nodoc: + equal?(other) or self.class == other.class and full_name == other.full_name + end + + ## + # A method/attribute is documented if any of the following is true: + # - it was marked with :nodoc:; + # - it has a comment; + # - it is an alias for a documented method; + # - it has a +#see+ method that is documented. + + def documented? + super or + (is_alias_for and is_alias_for.documented?) or + (see and see.documented?) + end + + ## + # A method/attribute to look at, + # in particular if this method/attribute has no documentation. + # + # It can be a method/attribute of the superclass or of an included module, + # including the Kernel module, which is always appended to the included + # modules. + # + # Returns +nil+ if there is no such method/attribute. + # The +#is_alias_for+ method/attribute, if any, is not included. + # + # Templates may generate a "see also ..." if this method/attribute + # has documentation, and "see ..." if it does not. + + def see + @see = find_see if @see == false + @see + end + + ## + # Sets the store for this class or module and its contained code objects. + + def store= store + super + + @file = @store.add_file @file.full_name if @file + end + + def find_see # :nodoc: + return nil if singleton || is_alias_for + + # look for the method + other = find_method_or_attribute name + return other if other + + # if it is a setter, look for a getter + return nil unless name =~ /[a-z_]=$/i # avoid == or === + return find_method_or_attribute name[0..-2] + end + + def find_method_or_attribute name # :nodoc: + return nil unless parent.respond_to? :ancestors + + searched = parent.ancestors + kernel = @store.modules_hash['Kernel'] + + searched << kernel if kernel && + parent != kernel && !searched.include?(kernel) + + searched.each do |ancestor| + next if String === ancestor + next if parent == ancestor + + other = ancestor.find_method_named('#' << name) || + ancestor.find_attribute_named(name) + + return other if other + end + + nil + end + + ## + # Abstract method. Contexts in their building phase call this + # to register a new alias for this known method/attribute. + # + # - creates a new AnyMethod/Attribute named <tt>an_alias.new_name</tt>; + # - adds +self+ as an alias for the new method or attribute + # - adds the method or attribute to #aliases + # - adds the method or attribute to +context+. + + def add_alias(an_alias, context) + raise NotImplementedError + end + + ## + # HTML fragment reference for this method + + def aref + type = singleton ? 'c' : 'i' + # % characters are not allowed in html names => dash instead + "#{aref_prefix}-#{type}-#{html_name}" + end + + ## + # Prefix for +aref+, defined by subclasses. + + def aref_prefix + raise NotImplementedError + end + + ## + # Attempts to sanitize the content passed by the Ruby parser: + # remove outer parentheses, etc. + + def block_params=(value) + # 'yield.to_s' or 'assert yield, msg' + return @block_params = '' if value =~ /^[\.,]/ + + # remove trailing 'if/unless ...' + return @block_params = '' if value =~ /^(if|unless)\s/ + + value = $1.strip if value =~ /^(.+)\s(if|unless)\s/ + + # outer parentheses + value = $1 if value =~ /^\s*\((.*)\)\s*$/ + value = value.strip + + # proc/lambda + return @block_params = $1 if value =~ /^(proc|lambda)(\s*\{|\sdo)/ + + # surrounding +...+ or [...] + value = $1.strip if value =~ /^\+(.*)\+$/ + value = $1.strip if value =~ /^\[(.*)\]$/ + + return @block_params = '' if value.empty? + + # global variable + return @block_params = 'str' if value =~ /^\$[&0-9]$/ + + # wipe out array/hash indices + value.gsub!(/(\w)\[[^\[]+\]/, '\1') + + # remove @ from class/instance variables + value.gsub!(/@@?([a-z0-9_]+)/, '\1') + + # method calls => method name + value.gsub!(/([A-Z:a-z0-9_]+)\.([a-z0-9_]+)(\s*\(\s*[a-z0-9_.,\s]*\s*\)\s*)?/) do + case $2 + when 'to_s' then $1 + when 'const_get' then 'const' + when 'new' then + $1.split('::').last. # ClassName => class_name + gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2'). + gsub(/([a-z\d])([A-Z])/,'\1_\2'). + downcase + else + $2 + end + end + + # class prefixes + value.gsub!(/[A-Za-z0-9_:]+::/, '') + + # simple expressions + value = $1 if value =~ /^([a-z0-9_]+)\s*[-*+\/]/ + + @block_params = value.strip + end + + ## + # HTML id-friendly method/attribute name + + def html_name + require 'cgi' + + CGI.escape(@name.gsub('-', '-2D')).gsub('%','-').sub(/^-/, '') + end + + ## + # Full method/attribute name including namespace + + def full_name + @full_name ||= "#{parent_name}#{pretty_name}" + end + + def inspect # :nodoc: + alias_for = @is_alias_for ? " (alias for #{@is_alias_for.name})" : nil + visibility = self.visibility + visibility = "forced #{visibility}" if force_documentation + "#<%s:0x%x %s (%s)%s>" % [ + self.class, object_id, + full_name, + visibility, + alias_for, + ] + end + + ## + # '::' for a class method/attribute, '#' for an instance method. + + def name_prefix + @singleton ? '::' : '#' + end + + ## + # Name for output to HTML. For class methods the full name with a "." is + # used like +SomeClass.method_name+. For instance methods the class name is + # used if +context+ does not match the parent. + # + # This is to help prevent people from using :: to call class methods. + + def output_name context + return "#{name_prefix}#{@name}" if context == parent + + "#{parent_name}#{@singleton ? '.' : '#'}#{@name}" + end + + ## + # Method/attribute name with class/instance indicator + + def pretty_name + "#{name_prefix}#{@name}" + end + + ## + # Type of method/attribute (class or instance) + + def type + singleton ? 'class' : 'instance' + end + + ## + # Path to this method for use with HTML generator output. + + def path + "#{@parent.path}##{aref}" + end + + ## + # Name of our parent with special handling for un-marshaled methods + + def parent_name + @parent_name || super + end + + def pretty_print q # :nodoc: + alias_for = + if @is_alias_for.respond_to? :name then + "alias for #{@is_alias_for.name}" + elsif Array === @is_alias_for then + "alias for #{@is_alias_for.last}" + end + + q.group 2, "[#{self.class.name} #{full_name} #{visibility}", "]" do + if alias_for then + q.breakable + q.text alias_for + end + + if text then + q.breakable + q.text "text:" + q.breakable + q.pp @text + end + + unless comment.empty? then + q.breakable + q.text "comment:" + q.breakable + q.pp @comment + end + end + end + + ## + # Used by RDoc::Generator::JsonIndex to create a record for the search + # engine. + + def search_record + [ + @name, + full_name, + @name, + @parent.full_name, + path, + params, + snippet(@comment), + ] + end + + def to_s # :nodoc: + if @is_alias_for + "#{self.class.name}: #{full_name} -> #{is_alias_for}" + else + "#{self.class.name}: #{full_name}" + end + end + +end + diff --git a/jni/ruby/lib/rdoc/mixin.rb b/jni/ruby/lib/rdoc/mixin.rb new file mode 100644 index 0000000..547744f --- /dev/null +++ b/jni/ruby/lib/rdoc/mixin.rb @@ -0,0 +1,120 @@ +## +# A Mixin adds features from a module into another context. RDoc::Include and +# RDoc::Extend are both mixins. + +class RDoc::Mixin < RDoc::CodeObject + + ## + # Name of included module + + attr_accessor :name + + ## + # Creates a new Mixin for +name+ with +comment+ + + def initialize(name, comment) + super() + @name = name + self.comment = comment + @module = nil # cache for module if found + end + + ## + # Mixins are sorted by name + + def <=> other + return unless self.class === other + + name <=> other.name + end + + def == other # :nodoc: + self.class === other and @name == other.name + end + + alias eql? == # :nodoc: + + ## + # Full name based on #module + + def full_name + m = self.module + RDoc::ClassModule === m ? m.full_name : @name + end + + def hash # :nodoc: + [@name, self.module].hash + end + + def inspect # :nodoc: + "#<%s:0x%x %s.%s %s>" % [ + self.class, + object_id, + parent_name, self.class.name.downcase, @name, + ] + end + + ## + # Attempts to locate the included module object. Returns the name if not + # known. + # + # The scoping rules of Ruby to resolve the name of an included module are: + # - first look into the children of the current context; + # - if not found, look into the children of included modules, + # in reverse inclusion order; + # - if still not found, go up the hierarchy of names. + # + # This method has <code>O(n!)</code> behavior when the module calling + # include is referencing nonexistent modules. Avoid calling #module until + # after all the files are parsed. This behavior is due to ruby's constant + # lookup behavior. + # + # As of the beginning of October, 2011, no gem includes nonexistent modules. + + def module + return @module if @module + + # search the current context + return @name unless parent + full_name = parent.child_name(@name) + @module = @store.modules_hash[full_name] + return @module if @module + return @name if @name =~ /^::/ + + # search the includes before this one, in reverse order + searched = parent.includes.take_while { |i| i != self }.reverse + searched.each do |i| + inc = i.module + next if String === inc + full_name = inc.child_name(@name) + @module = @store.modules_hash[full_name] + return @module if @module + end + + # go up the hierarchy of names + up = parent.parent + while up + full_name = up.child_name(@name) + @module = @store.modules_hash[full_name] + return @module if @module + up = up.parent + end + + @name + end + + ## + # Sets the store for this class or module and its contained code objects. + + def store= store + super + + @file = @store.add_file @file.full_name if @file + end + + def to_s # :nodoc: + "#{self.class.name.downcase} #@name in: #{parent}" + end + +end + diff --git a/jni/ruby/lib/rdoc/normal_class.rb b/jni/ruby/lib/rdoc/normal_class.rb new file mode 100644 index 0000000..7589e26 --- /dev/null +++ b/jni/ruby/lib/rdoc/normal_class.rb @@ -0,0 +1,92 @@ +## +# A normal class, neither singleton nor anonymous + +class RDoc::NormalClass < RDoc::ClassModule + + ## + # The ancestors of this class including modules. Unlike Module#ancestors, + # this class is not included in the result. The result will contain both + # RDoc::ClassModules and Strings. + + def ancestors + if String === superclass then + super << superclass + elsif superclass then + ancestors = super + ancestors << superclass + ancestors.concat superclass.ancestors + else + super + end + end + + def aref_prefix # :nodoc: + 'class' + end + + ## + # The definition of this class, <tt>class MyClassName</tt> + + def definition + "class #{full_name}" + end + + def direct_ancestors + superclass ? super + [superclass] : super + end + + def inspect # :nodoc: + superclass = @superclass ? " < #{@superclass}" : nil + "<%s:0x%x class %s%s includes: %p extends: %p attributes: %p methods: %p aliases: %p>" % [ + self.class, object_id, + full_name, superclass, @includes, @extends, @attributes, @method_list, @aliases + ] + end + + def to_s # :nodoc: + display = "#{self.class.name} #{self.full_name}" + if superclass + display << ' < ' << (superclass.is_a?(String) ? superclass : superclass.full_name) + end + display << ' -> ' << is_alias_for.to_s if is_alias_for + display + end + + def pretty_print q # :nodoc: + superclass = @superclass ? " < #{@superclass}" : nil + + q.group 2, "[class #{full_name}#{superclass} ", "]" do + q.breakable + q.text "includes:" + q.breakable + q.seplist @includes do |inc| q.pp inc end + + q.breakable + q.text "constants:" + q.breakable + q.seplist @constants do |const| q.pp const end + + q.breakable + q.text "attributes:" + q.breakable + q.seplist @attributes do |attr| q.pp attr end + + q.breakable + q.text "methods:" + q.breakable + q.seplist @method_list do |meth| q.pp meth end + + q.breakable + q.text "aliases:" + q.breakable + q.seplist @aliases do |aliaz| q.pp aliaz end + + q.breakable + q.text "comment:" + q.breakable + q.pp comment + end + end + +end + diff --git a/jni/ruby/lib/rdoc/normal_module.rb b/jni/ruby/lib/rdoc/normal_module.rb new file mode 100644 index 0000000..961c431 --- /dev/null +++ b/jni/ruby/lib/rdoc/normal_module.rb @@ -0,0 +1,73 @@ +## +# A normal module, like NormalClass + +class RDoc::NormalModule < RDoc::ClassModule + + def aref_prefix # :nodoc: + 'module' + end + + def inspect # :nodoc: + "#<%s:0x%x module %s includes: %p extends: %p attributes: %p methods: %p aliases: %p>" % [ + self.class, object_id, + full_name, @includes, @extends, @attributes, @method_list, @aliases + ] + end + + ## + # The definition of this module, <tt>module MyModuleName</tt> + + def definition + "module #{full_name}" + end + + ## + # This is a module, returns true + + def module? + true + end + + def pretty_print q # :nodoc: + q.group 2, "[module #{full_name}: ", "]" do + q.breakable + q.text "includes:" + q.breakable + q.seplist @includes do |inc| q.pp inc end + q.breakable + + q.breakable + q.text "constants:" + q.breakable + q.seplist @constants do |const| q.pp const end + + q.text "attributes:" + q.breakable + q.seplist @attributes do |attr| q.pp attr end + q.breakable + + q.text "methods:" + q.breakable + q.seplist @method_list do |meth| q.pp meth end + q.breakable + + q.text "aliases:" + q.breakable + q.seplist @aliases do |aliaz| q.pp aliaz end + q.breakable + + q.text "comment:" + q.breakable + q.pp comment + end + end + + ## + # Modules don't have one, raises NoMethodError + + def superclass + raise NoMethodError, "#{full_name} is a module" + end + +end + diff --git a/jni/ruby/lib/rdoc/options.rb b/jni/ruby/lib/rdoc/options.rb new file mode 100644 index 0000000..5779d35 --- /dev/null +++ b/jni/ruby/lib/rdoc/options.rb @@ -0,0 +1,1251 @@ +require 'optparse' +require 'pathname' + +## +# RDoc::Options handles the parsing and storage of options +# +# == Saved Options +# +# You can save some options like the markup format in the +# <tt>.rdoc_options</tt> file in your gem. The easiest way to do this is: +# +# rdoc --markup tomdoc --write-options +# +# Which will automatically create the file and fill it with the options you +# specified. +# +# The following options will not be saved since they interfere with the user's +# preferences or with the normal operation of RDoc: +# +# * +--coverage-report+ +# * +--dry-run+ +# * +--encoding+ +# * +--force-update+ +# * +--format+ +# * +--pipe+ +# * +--quiet+ +# * +--template+ +# * +--verbose+ +# +# == Custom Options +# +# Generators can hook into RDoc::Options to add generator-specific command +# line options. +# +# When <tt>--format</tt> is encountered in ARGV, RDoc calls ::setup_options on +# the generator class to add extra options to the option parser. Options for +# custom generators must occur after <tt>--format</tt>. <tt>rdoc --help</tt> +# will list options for all installed generators. +# +# Example: +# +# class RDoc::Generator::Spellcheck +# RDoc::RDoc.add_generator self +# +# def self.setup_options rdoc_options +# op = rdoc_options.option_parser +# +# op.on('--spell-dictionary DICTIONARY', +# RDoc::Options::Path) do |dictionary| +# rdoc_options.spell_dictionary = dictionary +# end +# end +# end +# +# Of course, RDoc::Options does not respond to +spell_dictionary+ by default +# so you will need to add it: +# +# class RDoc::Options +# +# ## +# # The spell dictionary used by the spell-checking plugin. +# +# attr_accessor :spell_dictionary +# +# end +# +# == Option Validators +# +# OptionParser validators will validate and cast user input values. In +# addition to the validators that ship with OptionParser (String, Integer, +# Float, TrueClass, FalseClass, Array, Regexp, Date, Time, URI, etc.), +# RDoc::Options adds Path, PathArray and Template. + +class RDoc::Options + + ## + # The deprecated options. + + DEPRECATED = { + '--accessor' => 'support discontinued', + '--diagram' => 'support discontinued', + '--help-output' => 'support discontinued', + '--image-format' => 'was an option for --diagram', + '--inline-source' => 'source code is now always inlined', + '--merge' => 'ri now always merges class information', + '--one-file' => 'support discontinued', + '--op-name' => 'support discontinued', + '--opname' => 'support discontinued', + '--promiscuous' => 'files always only document their content', + '--ri-system' => 'Ruby installers use other techniques', + } + + ## + # RDoc options ignored (or handled specially) by --write-options + + SPECIAL = %w[ + coverage_report + dry_run + encoding + files + force_output + force_update + generator + generator_name + generator_options + generators + op_dir + option_parser + pipe + rdoc_include + root + static_path + stylesheet_url + template + template_dir + update_output_dir + verbosity + write_options + ] + + ## + # Option validator for OptionParser that matches a directory that exists on + # the filesystem. + + Directory = Object.new + + ## + # Option validator for OptionParser that matches a file or directory that + # exists on the filesystem. + + Path = Object.new + + ## + # Option validator for OptionParser that matches a comma-separated list of + # files or directories that exist on the filesystem. + + PathArray = Object.new + + ## + # Option validator for OptionParser that matches a template directory for an + # installed generator that lives in + # <tt>"rdoc/generator/template/#{template_name}"</tt> + + Template = Object.new + + ## + # Character-set for HTML output. #encoding is preferred over #charset + + attr_accessor :charset + + ## + # If true, RDoc will not write any files. + + attr_accessor :dry_run + + ## + # The output encoding. All input files will be transcoded to this encoding. + # + # The default encoding is UTF-8. This is set via --encoding. + + attr_accessor :encoding + + ## + # Files matching this pattern will be excluded + + attr_accessor :exclude + + ## + # The list of files to be processed + + attr_accessor :files + + ## + # Create the output even if the output directory does not look + # like an rdoc output directory + + attr_accessor :force_output + + ## + # Scan newer sources than the flag file if true. + + attr_accessor :force_update + + ## + # Formatter to mark up text with + + attr_accessor :formatter + + ## + # Description of the output generator (set with the <tt>--format</tt> option) + + attr_accessor :generator + + ## + # For #== + + attr_reader :generator_name # :nodoc: + + ## + # Loaded generator options. Used to prevent --help from loading the same + # options multiple times. + + attr_accessor :generator_options + + ## + # Old rdoc behavior: hyperlink all words that match a method name, + # even if not preceded by '#' or '::' + + attr_accessor :hyperlink_all + + ## + # Include line numbers in the source code + + attr_accessor :line_numbers + + ## + # The output locale. + + attr_accessor :locale + + ## + # The directory where locale data live. + + attr_accessor :locale_dir + + ## + # Name of the file, class or module to display in the initial index page (if + # not specified the first file we encounter is used) + + attr_accessor :main_page + + ## + # The default markup format. The default is 'rdoc'. 'markdown', 'tomdoc' + # and 'rd' are also built-in. + + attr_accessor :markup + + ## + # If true, only report on undocumented files + + attr_accessor :coverage_report + + ## + # The name of the output directory + + attr_accessor :op_dir + + ## + # The OptionParser for this instance + + attr_accessor :option_parser + + ## + # Output heading decorations? + attr_accessor :output_decoration + + ## + # Directory where guides, FAQ, and other pages not associated with a class + # live. You may leave this unset if these are at the root of your project. + + attr_accessor :page_dir + + ## + # Is RDoc in pipe mode? + + attr_accessor :pipe + + ## + # Array of directories to search for files to satisfy an :include: + + attr_accessor :rdoc_include + + ## + # Root of the source documentation will be generated for. Set this when + # building documentation outside the source directory. Defaults to the + # current directory. + + attr_accessor :root + + ## + # Include the '#' at the front of hyperlinked instance method names + + attr_accessor :show_hash + + ## + # Directory to copy static files from + + attr_accessor :static_path + + ## + # The number of columns in a tab + + attr_accessor :tab_width + + ## + # Template to be used when generating output + + attr_accessor :template + + ## + # Directory the template lives in + + attr_accessor :template_dir + + ## + # Additional template stylesheets + + attr_accessor :template_stylesheets + + ## + # Documentation title + + attr_accessor :title + + ## + # Should RDoc update the timestamps in the output dir? + + attr_accessor :update_output_dir + + ## + # Verbosity, zero means quiet + + attr_accessor :verbosity + + ## + # URL of web cvs frontend + + attr_accessor :webcvs + + ## + # Minimum visibility of a documented method. One of +:public+, +:protected+, + # +:private+ or +:nodoc+. + # + # The +:nodoc+ visibility ignores all directives related to visibility. The + # other visibilities may be overridden on a per-method basis with the :doc: + # directive. + + attr_reader :visibility + + def initialize # :nodoc: + init_ivars + end + + def init_ivars # :nodoc: + @dry_run = false + @exclude = [] + @files = nil + @force_output = false + @force_update = true + @generator = nil + @generator_name = nil + @generator_options = [] + @generators = RDoc::RDoc::GENERATORS + @hyperlink_all = false + @line_numbers = false + @locale = nil + @locale_name = nil + @locale_dir = 'locale' + @main_page = nil + @markup = 'rdoc' + @coverage_report = false + @op_dir = nil + @page_dir = nil + @pipe = false + @output_decoration = true + @rdoc_include = [] + @root = Pathname(Dir.pwd) + @show_hash = false + @static_path = [] + @stylesheet_url = nil # TODO remove in RDoc 4 + @tab_width = 8 + @template = nil + @template_dir = nil + @template_stylesheets = [] + @title = nil + @update_output_dir = true + @verbosity = 1 + @visibility = :protected + @webcvs = nil + @write_options = false + + if Object.const_defined? :Encoding then + @encoding = Encoding::UTF_8 + @charset = @encoding.name + else + @encoding = nil + @charset = 'UTF-8' + end + end + + def init_with map # :nodoc: + init_ivars + + encoding = map['encoding'] + @encoding = if Object.const_defined? :Encoding then + encoding ? Encoding.find(encoding) : encoding + end + + @charset = map['charset'] + @exclude = map['exclude'] + @generator_name = map['generator_name'] + @hyperlink_all = map['hyperlink_all'] + @line_numbers = map['line_numbers'] + @locale_name = map['locale_name'] + @locale_dir = map['locale_dir'] + @main_page = map['main_page'] + @markup = map['markup'] + @op_dir = map['op_dir'] + @show_hash = map['show_hash'] + @tab_width = map['tab_width'] + @template_dir = map['template_dir'] + @title = map['title'] + @visibility = map['visibility'] + @webcvs = map['webcvs'] + + @rdoc_include = sanitize_path map['rdoc_include'] + @static_path = sanitize_path map['static_path'] + end + + def yaml_initialize tag, map # :nodoc: + init_with map + end + + def == other # :nodoc: + self.class === other and + @encoding == other.encoding and + @generator_name == other.generator_name and + @hyperlink_all == other.hyperlink_all and + @line_numbers == other.line_numbers and + @locale == other.locale and + @locale_dir == other.locale_dir and + @main_page == other.main_page and + @markup == other.markup and + @op_dir == other.op_dir and + @rdoc_include == other.rdoc_include and + @show_hash == other.show_hash and + @static_path == other.static_path and + @tab_width == other.tab_width and + @template == other.template and + @title == other.title and + @visibility == other.visibility and + @webcvs == other.webcvs + end + + ## + # Check that the files on the command line exist + + def check_files + @files.delete_if do |file| + if File.exist? file then + if File.readable? file then + false + else + warn "file '#{file}' not readable" + + true + end + else + warn "file '#{file}' not found" + + true + end + end + end + + ## + # Ensure only one generator is loaded + + def check_generator + if @generator then + raise OptionParser::InvalidOption, + "generator already set to #{@generator_name}" + end + end + + ## + # Set the title, but only if not already set. Used to set the title + # from a source file, so that a title set from the command line + # will have the priority. + + def default_title=(string) + @title ||= string + end + + ## + # For dumping YAML + + def encode_with coder # :nodoc: + encoding = @encoding ? @encoding.name : nil + + coder.add 'encoding', encoding + coder.add 'static_path', sanitize_path(@static_path) + coder.add 'rdoc_include', sanitize_path(@rdoc_include) + + ivars = instance_variables.map { |ivar| ivar.to_s[1..-1] } + ivars -= SPECIAL + + ivars.sort.each do |ivar| + coder.add ivar, instance_variable_get("@#{ivar}") + end + end + + ## + # Completes any unfinished option setup business such as filtering for + # existent files, creating a regexp for #exclude and setting a default + # #template. + + def finish + @op_dir ||= 'doc' + + @rdoc_include << "." if @rdoc_include.empty? + root = @root.to_s + @rdoc_include << root unless @rdoc_include.include?(root) + + if @exclude.nil? or Regexp === @exclude then + # done, #finish is being re-run + elsif @exclude.empty? then + @exclude = nil + else + @exclude = Regexp.new(@exclude.join("|")) + end + + finish_page_dir + + check_files + + # If no template was specified, use the default template for the output + # formatter + + unless @template then + @template = @generator_name + @template_dir = template_dir_for @template + end + + if @locale_name + @locale = RDoc::I18n::Locale[@locale_name] + @locale.load(@locale_dir) + else + @locale = nil + end + + self + end + + ## + # Fixes the page_dir to be relative to the root_dir and adds the page_dir to + # the files list. + + def finish_page_dir + return unless @page_dir + + @files << @page_dir.to_s + + page_dir = @page_dir.expand_path.relative_path_from @root + + @page_dir = page_dir + end + + ## + # Returns a properly-space list of generators and their descriptions. + + def generator_descriptions + lengths = [] + + generators = RDoc::RDoc::GENERATORS.map do |name, generator| + lengths << name.length + + description = generator::DESCRIPTION if + generator.const_defined? :DESCRIPTION + + [name, description] + end + + longest = lengths.max + + generators.sort.map do |name, description| + if description then + " %-*s - %s" % [longest, name, description] + else + " #{name}" + end + end.join "\n" + end + + ## + # Parses command line options. + + def parse argv + ignore_invalid = true + + argv.insert(0, *ENV['RDOCOPT'].split) if ENV['RDOCOPT'] + + opts = OptionParser.new do |opt| + @option_parser = opt + opt.program_name = File.basename $0 + opt.version = RDoc::VERSION + opt.release = nil + opt.summary_indent = ' ' * 4 + opt.banner = <<-EOF +Usage: #{opt.program_name} [options] [names...] + + Files are parsed, and the information they contain collected, before any + output is produced. This allows cross references between all files to be + resolved. If a name is a directory, it is traversed. If no names are + specified, all Ruby files in the current directory (and subdirectories) are + processed. + + How RDoc generates output depends on the output formatter being used, and on + the options you give. + + Options can be specified via the RDOCOPT environment variable, which + functions similar to the RUBYOPT environment variable for ruby. + + $ export RDOCOPT="--show-hash" + + will make rdoc show hashes in method links by default. Command-line options + always will override those in RDOCOPT. + + Available formatters: + +#{generator_descriptions} + + RDoc understands the following file formats: + + EOF + + parsers = Hash.new { |h,parser| h[parser] = [] } + + RDoc::Parser.parsers.each do |regexp, parser| + parsers[parser.name.sub('RDoc::Parser::', '')] << regexp.source + end + + parsers.sort.each do |parser, regexp| + opt.banner << " - #{parser}: #{regexp.join ', '}\n" + end + opt.banner << " - TomDoc: Only in ruby files\n" + + opt.banner << "\n The following options are deprecated:\n\n" + + name_length = DEPRECATED.keys.sort_by { |k| k.length }.last.length + + DEPRECATED.sort_by { |k,| k }.each do |name, reason| + opt.banner << " %*1$2$s %3$s\n" % [-name_length, name, reason] + end + + opt.accept Template do |template| + template_dir = template_dir_for template + + unless template_dir then + $stderr.puts "could not find template #{template}" + nil + else + [template, template_dir] + end + end + + opt.accept Directory do |directory| + directory = File.expand_path directory + + raise OptionParser::InvalidArgument unless File.directory? directory + + directory + end + + opt.accept Path do |path| + path = File.expand_path path + + raise OptionParser::InvalidArgument unless File.exist? path + + path + end + + opt.accept PathArray do |paths,| + paths = if paths then + paths.split(',').map { |d| d unless d.empty? } + end + + paths.map do |path| + path = File.expand_path path + + raise OptionParser::InvalidArgument unless File.exist? path + + path + end + end + + opt.separator nil + opt.separator "Parsing options:" + opt.separator nil + + if Object.const_defined? :Encoding then + opt.on("--encoding=ENCODING", "-e", Encoding.list.map { |e| e.name }, + "Specifies the output encoding. All files", + "read will be converted to this encoding.", + "The default encoding is UTF-8.", + "--encoding is preferred over --charset") do |value| + @encoding = Encoding.find value + @charset = @encoding.name # may not be valid value + end + + opt.separator nil + end + + + opt.on("--locale=NAME", + "Specifies the output locale.") do |value| + @locale_name = value + end + + opt.on("--locale-data-dir=DIR", + "Specifies the directory where locale data live.") do |value| + @locale_dir = value + end + + opt.separator nil + + opt.on("--all", "-a", + "Synonym for --visibility=private.") do |value| + @visibility = :private + end + + opt.separator nil + + opt.on("--exclude=PATTERN", "-x", Regexp, + "Do not process files or directories", + "matching PATTERN.") do |value| + @exclude << value + end + + opt.separator nil + + opt.on("--extension=NEW=OLD", "-E", + "Treat files ending with .new as if they", + "ended with .old. Using '-E cgi=rb' will", + "cause xxx.cgi to be parsed as a Ruby file.") do |value| + new, old = value.split(/=/, 2) + + unless new and old then + raise OptionParser::InvalidArgument, "Invalid parameter to '-E'" + end + + unless RDoc::Parser.alias_extension old, new then + raise OptionParser::InvalidArgument, "Unknown extension .#{old} to -E" + end + end + + opt.separator nil + + opt.on("--[no-]force-update", "-U", + "Forces rdoc to scan all sources even if", + "newer than the flag file.") do |value| + @force_update = value + end + + opt.separator nil + + opt.on("--pipe", "-p", + "Convert RDoc on stdin to HTML") do + @pipe = true + end + + opt.separator nil + + opt.on("--tab-width=WIDTH", "-w", Integer, + "Set the width of tab characters.") do |value| + raise OptionParser::InvalidArgument, + "#{value} is an invalid tab width" if value <= 0 + @tab_width = value + end + + opt.separator nil + + opt.on("--visibility=VISIBILITY", "-V", RDoc::VISIBILITIES + [:nodoc], + "Minimum visibility to document a method.", + "One of 'public', 'protected' (the default),", + "'private' or 'nodoc' (show everything)") do |value| + @visibility = value + end + + opt.separator nil + + markup_formats = RDoc::Text::MARKUP_FORMAT.keys.sort + + opt.on("--markup=MARKUP", markup_formats, + "The markup format for the named files.", + "The default is rdoc. Valid values are:", + markup_formats.join(', ')) do |value| + @markup = value + end + + opt.separator nil + + opt.on("--root=ROOT", Directory, + "Root of the source tree documentation", + "will be generated for. Set this when", + "building documentation outside the", + "source directory. Default is the", + "current directory.") do |root| + @root = Pathname(root) + end + + opt.separator nil + + opt.on("--page-dir=DIR", Directory, + "Directory where guides, your FAQ or", + "other pages not associated with a class", + "live. Set this when you don't store", + "such files at your project root.", + "NOTE: Do not use the same file name in", + "the page dir and the root of your project") do |page_dir| + @page_dir = Pathname(page_dir) + end + + opt.separator nil + opt.separator "Common generator options:" + opt.separator nil + + opt.on("--force-output", "-O", + "Forces rdoc to write the output files,", + "even if the output directory exists", + "and does not seem to have been created", + "by rdoc.") do |value| + @force_output = value + end + + opt.separator nil + + generator_text = @generators.keys.map { |name| " #{name}" }.sort + + opt.on("-f", "--fmt=FORMAT", "--format=FORMAT", @generators.keys, + "Set the output formatter. One of:", *generator_text) do |value| + check_generator + + @generator_name = value.downcase + setup_generator + end + + opt.separator nil + + opt.on("--include=DIRECTORIES", "-i", PathArray, + "Set (or add to) the list of directories to", + "be searched when satisfying :include:", + "requests. Can be used more than once.") do |value| + @rdoc_include.concat value.map { |dir| dir.strip } + end + + opt.separator nil + + opt.on("--[no-]coverage-report=[LEVEL]", "--[no-]dcov", "-C", Integer, + "Prints a report on undocumented items.", + "Does not generate files.") do |value| + value = 0 if value.nil? # Integer converts -C to nil + + @coverage_report = value + @force_update = true if value + end + + opt.separator nil + + opt.on("--output=DIR", "--op", "-o", + "Set the output directory.") do |value| + @op_dir = value + end + + opt.separator nil + + opt.on("-d", + "Deprecated --diagram option.", + "Prevents firing debug mode", + "with legacy invocation.") do |value| + end + + opt.separator nil + opt.separator 'HTML generator options:' + opt.separator nil + + opt.on("--charset=CHARSET", "-c", + "Specifies the output HTML character-set.", + "Use --encoding instead of --charset if", + "available.") do |value| + @charset = value + end + + opt.separator nil + + opt.on("--hyperlink-all", "-A", + "Generate hyperlinks for all words that", + "correspond to known methods, even if they", + "do not start with '#' or '::' (legacy", + "behavior).") do |value| + @hyperlink_all = value + end + + opt.separator nil + + opt.on("--main=NAME", "-m", + "NAME will be the initial page displayed.") do |value| + @main_page = value + end + + opt.separator nil + + opt.on("--[no-]line-numbers", "-N", + "Include line numbers in the source code.", + "By default, only the number of the first", + "line is displayed, in a leading comment.") do |value| + @line_numbers = value + end + + opt.separator nil + + opt.on("--show-hash", "-H", + "A name of the form #name in a comment is a", + "possible hyperlink to an instance method", + "name. When displayed, the '#' is removed", + "unless this option is specified.") do |value| + @show_hash = value + end + + opt.separator nil + + opt.on("--template=NAME", "-T", Template, + "Set the template used when generating", + "output. The default depends on the", + "formatter used.") do |(template, template_dir)| + @template = template + @template_dir = template_dir + end + + opt.separator nil + + opt.on("--template-stylesheets=FILES", PathArray, + "Set (or add to) the list of files to", + "include with the html template.") do |value| + @template_stylesheets << value + end + + opt.separator nil + + opt.on("--title=TITLE", "-t", + "Set TITLE as the title for HTML output.") do |value| + @title = value + end + + opt.separator nil + + opt.on("--copy-files=PATH", Path, + "Specify a file or directory to copy static", + "files from.", + "If a file is given it will be copied into", + "the output dir. If a directory is given the", + "entire directory will be copied.", + "You can use this multiple times") do |value| + @static_path << value + end + + opt.separator nil + + opt.on("--webcvs=URL", "-W", + "Specify a URL for linking to a web frontend", + "to CVS. If the URL contains a '\%s', the", + "name of the current file will be", + "substituted; if the URL doesn't contain a", + "'\%s', the filename will be appended to it.") do |value| + @webcvs = value + end + + opt.separator nil + opt.separator "ri generator options:" + opt.separator nil + + opt.on("--ri", "-r", + "Generate output for use by `ri`. The files", + "are stored in the '.rdoc' directory under", + "your home directory unless overridden by a", + "subsequent --op parameter, so no special", + "privileges are needed.") do |value| + check_generator + + @generator_name = "ri" + @op_dir ||= RDoc::RI::Paths::HOMEDIR + setup_generator + end + + opt.separator nil + + opt.on("--ri-site", "-R", + "Generate output for use by `ri`. The files", + "are stored in a site-wide directory,", + "making them accessible to others, so", + "special privileges are needed.") do |value| + check_generator + + @generator_name = "ri" + @op_dir = RDoc::RI::Paths.site_dir + setup_generator + end + + opt.separator nil + opt.separator "Generic options:" + opt.separator nil + + opt.on("--write-options", + "Write .rdoc_options to the current", + "directory with the given options. Not all", + "options will be used. See RDoc::Options", + "for details.") do |value| + @write_options = true + end + + opt.separator nil + + opt.on("--[no-]dry-run", + "Don't write any files") do |value| + @dry_run = value + end + + opt.separator nil + + opt.on("-D", "--[no-]debug", + "Displays lots on internal stuff.") do |value| + $DEBUG_RDOC = value + end + + opt.separator nil + + opt.on("--[no-]ignore-invalid", + "Ignore invalid options and continue", + "(default true).") do |value| + ignore_invalid = value + end + + opt.separator nil + + opt.on("--quiet", "-q", + "Don't show progress as we parse.") do |value| + @verbosity = 0 + end + + opt.separator nil + + opt.on("--verbose", "-V", + "Display extra progress as RDoc parses") do |value| + @verbosity = 2 + end + + opt.separator nil + + opt.on("--version", "-v", "print the version") do + puts opt.version + exit + end + + opt.separator nil + + opt.on("--help", "-h", "Display this help") do + RDoc::RDoc::GENERATORS.each_key do |generator| + setup_generator generator + end + + puts opt.help + exit + end + + opt.separator nil + end + + setup_generator 'darkfish' if + argv.grep(/\A(-f|--fmt|--format|-r|-R|--ri|--ri-site)\b/).empty? + + deprecated = [] + invalid = [] + + begin + opts.parse! argv + rescue OptionParser::ParseError => e + if DEPRECATED[e.args.first] then + deprecated << e.args.first + elsif %w[--format --ri -r --ri-site -R].include? e.args.first then + raise + else + invalid << e.args.join(' ') + end + + retry + end + + unless @generator then + @generator = RDoc::Generator::Darkfish + @generator_name = 'darkfish' + end + + if @pipe and not argv.empty? then + @pipe = false + invalid << '-p (with files)' + end + + unless quiet then + deprecated.each do |opt| + $stderr.puts 'option ' << opt << ' is deprecated: ' << DEPRECATED[opt] + end + end + + unless invalid.empty? then + invalid = "invalid options: #{invalid.join ', '}" + + if ignore_invalid then + unless quiet then + $stderr.puts invalid + $stderr.puts '(invalid options are ignored)' + end + else + unless quiet then + $stderr.puts opts + end + $stderr.puts invalid + exit 1 + end + end + + @files = argv.dup + + finish + + if @write_options then + write_options + exit + end + + self + end + + ## + # Don't display progress as we process the files + + def quiet + @verbosity.zero? + end + + ## + # Set quietness to +bool+ + + def quiet= bool + @verbosity = bool ? 0 : 1 + end + + ## + # Removes directories from +path+ that are outside the current directory + + def sanitize_path path + require 'pathname' + dot = Pathname.new('.').expand_path + + path.reject do |item| + path = Pathname.new(item).expand_path + relative = path.relative_path_from(dot).to_s + relative.start_with? '..' + end + end + + ## + # Set up an output generator for the named +generator_name+. + # + # If the found generator responds to :setup_options it will be called with + # the options instance. This allows generators to add custom options or set + # default options. + + def setup_generator generator_name = @generator_name + @generator = @generators[generator_name] + + unless @generator then + raise OptionParser::InvalidArgument, + "Invalid output formatter #{generator_name}" + end + + return if @generator_options.include? @generator + + @generator_name = generator_name + @generator_options << @generator + + if @generator.respond_to? :setup_options then + @option_parser ||= OptionParser.new + @generator.setup_options self + end + end + + ## + # Finds the template dir for +template+ + + def template_dir_for template + template_path = File.join 'rdoc', 'generator', 'template', template + + $LOAD_PATH.map do |path| + File.join File.expand_path(path), template_path + end.find do |dir| + File.directory? dir + end + end + + ## + # This is compatibility code for syck + + def to_yaml opts = {} # :nodoc: + return super if YAML.const_defined?(:ENGINE) and not YAML::ENGINE.syck? + + YAML.quick_emit self, opts do |out| + out.map taguri, to_yaml_style do |map| + encode_with map + end + end + end + + # Sets the minimum visibility of a documented method. + # + # Accepts +:public+, +:protected+, +:private+, +:nodoc+, or +:all+. + # + # When +:all+ is passed, visibility is set to +:private+, similarly to + # RDOCOPT="--all", see #visibility for more information. + + def visibility= visibility + case visibility + when :all + @visibility = :private + else + @visibility = visibility + end + end + + ## + # Displays a warning using Kernel#warn if we're being verbose + + def warn message + super message if @verbosity > 1 + end + + ## + # Writes the YAML file .rdoc_options to the current directory containing the + # parsed options. + + def write_options + RDoc.load_yaml + + open '.rdoc_options', 'w' do |io| + io.set_encoding Encoding::UTF_8 if Object.const_defined? :Encoding + + YAML.dump self, io + end + end + +end + diff --git a/jni/ruby/lib/rdoc/parser.rb b/jni/ruby/lib/rdoc/parser.rb new file mode 100644 index 0000000..4da7f00 --- /dev/null +++ b/jni/ruby/lib/rdoc/parser.rb @@ -0,0 +1,310 @@ +# -*- coding: us-ascii -*- + +## +# A parser is simple a class that subclasses RDoc::Parser and implements #scan +# to fill in an RDoc::TopLevel with parsed data. +# +# The initialize method takes an RDoc::TopLevel to fill with parsed content, +# the name of the file to be parsed, the content of the file, an RDoc::Options +# object and an RDoc::Stats object to inform the user of parsed items. The +# scan method is then called to parse the file and must return the +# RDoc::TopLevel object. By calling super these items will be set for you. +# +# In order to be used by RDoc the parser needs to register the file extensions +# it can parse. Use ::parse_files_matching to register extensions. +# +# require 'rdoc' +# +# class RDoc::Parser::Xyz < RDoc::Parser +# parse_files_matching /\.xyz$/ +# +# def initialize top_level, file_name, content, options, stats +# super +# +# # extra initialization if needed +# end +# +# def scan +# # parse file and fill in @top_level +# end +# end + +class RDoc::Parser + + @parsers = [] + + class << self + + ## + # An Array of arrays that maps file extension (or name) regular + # expressions to parser classes that will parse matching filenames. + # + # Use parse_files_matching to register a parser's file extensions. + + attr_reader :parsers + + end + + ## + # The name of the file being parsed + + attr_reader :file_name + + ## + # Alias an extension to another extension. After this call, files ending + # "new_ext" will be parsed using the same parser as "old_ext" + + def self.alias_extension(old_ext, new_ext) + old_ext = old_ext.sub(/^\.(.*)/, '\1') + new_ext = new_ext.sub(/^\.(.*)/, '\1') + + parser = can_parse_by_name "xxx.#{old_ext}" + return false unless parser + + RDoc::Parser.parsers.unshift [/\.#{new_ext}$/, parser] + + true + end + + ## + # Determines if the file is a "binary" file which basically means it has + # content that an RDoc parser shouldn't try to consume. + + def self.binary?(file) + return false if file =~ /\.(rdoc|txt)$/ + + s = File.read(file, 1024) or return false + + have_encoding = s.respond_to? :encoding + + return true if s[0, 2] == Marshal.dump('')[0, 2] or s.index("\x00") + + if have_encoding then + mode = "r" + s.sub!(/\A#!.*\n/, '') # assume shebang line isn't longer than 1024. + encoding = s[/^\s*\#\s*(?:-\*-\s*)?(?:en)?coding:\s*([^\s;]+?)(?:-\*-|[\s;])/, 1] + mode = "rb:#{encoding}" if encoding + s = File.open(file, mode) {|f| f.gets(nil, 1024)} + + not s.valid_encoding? + else + if 0.respond_to? :fdiv then + s.count("\x00-\x7F", "^ -~\t\r\n").fdiv(s.size) > 0.3 + else # HACK 1.8.6 + (s.count("\x00-\x7F", "^ -~\t\r\n").to_f / s.size) > 0.3 + end + end + end + + ## + # Processes common directives for CodeObjects for the C and Ruby parsers. + # + # Applies +directive+'s +value+ to +code_object+, if appropriate + + def self.process_directive code_object, directive, value + warn "RDoc::Parser::process_directive is deprecated and wil be removed in RDoc 4. Use RDoc::Markup::PreProcess#handle_directive instead" if $-w + + case directive + when 'nodoc' then + code_object.document_self = nil # notify nodoc + code_object.document_children = value.downcase != 'all' + when 'doc' then + code_object.document_self = true + code_object.force_documentation = true + when 'yield', 'yields' then + # remove parameter &block + code_object.params.sub!(/,?\s*&\w+/, '') if code_object.params + + code_object.block_params = value + when 'arg', 'args' then + code_object.params = value + end + end + + ## + # Checks if +file+ is a zip file in disguise. Signatures from + # http://www.garykessler.net/library/file_sigs.html + + def self.zip? file + zip_signature = File.read file, 4 + + zip_signature == "PK\x03\x04" or + zip_signature == "PK\x05\x06" or + zip_signature == "PK\x07\x08" + rescue + false + end + + ## + # Return a parser that can handle a particular extension + + def self.can_parse file_name + parser = can_parse_by_name file_name + + # HACK Selenium hides a jar file using a .txt extension + return if parser == RDoc::Parser::Simple and zip? file_name + + parser + end + + ## + # Returns a parser that can handle the extension for +file_name+. This does + # not depend upon the file being readable. + + def self.can_parse_by_name file_name + _, parser = RDoc::Parser.parsers.find { |regexp,| regexp =~ file_name } + + # The default parser must not parse binary files + ext_name = File.extname file_name + return parser if ext_name.empty? + + if parser == RDoc::Parser::Simple and ext_name !~ /txt|rdoc/ then + case check_modeline file_name + when nil, 'rdoc' then # continue + else return nil + end + end + + parser + rescue Errno::EACCES + end + + ## + # Returns the file type from the modeline in +file_name+ + + def self.check_modeline file_name + line = open file_name do |io| + io.gets + end + + /-\*-\s*(.*?\S)\s*-\*-/ =~ line + + return nil unless type = $1 + + if /;/ =~ type then + return nil unless /(?:\s|\A)mode:\s*([^\s;]+)/i =~ type + type = $1 + end + + return nil if /coding:/i =~ type + + type.downcase + rescue ArgumentError # invalid byte sequence, etc. + end + + ## + # Finds and instantiates the correct parser for the given +file_name+ and + # +content+. + + def self.for top_level, file_name, content, options, stats + return if binary? file_name + + parser = use_markup content + + unless parser then + parse_name = file_name + + # If no extension, look for shebang + if file_name !~ /\.\w+$/ && content =~ %r{\A#!(.+)} then + shebang = $1 + case shebang + when %r{env\s+ruby}, %r{/ruby} + parse_name = 'dummy.rb' + end + end + + parser = can_parse parse_name + end + + return unless parser + + content = remove_modeline content + + parser.new top_level, file_name, content, options, stats + rescue SystemCallError + nil + end + + ## + # Record which file types this parser can understand. + # + # It is ok to call this multiple times. + + def self.parse_files_matching(regexp) + RDoc::Parser.parsers.unshift [regexp, self] + end + + ## + # Removes an emacs-style modeline from the first line of the document + + def self.remove_modeline content + content.sub(/\A.*-\*-\s*(.*?\S)\s*-\*-.*\r?\n/, '') + end + + ## + # If there is a <tt>markup: parser_name</tt> comment at the front of the + # file, use it to determine the parser. For example: + # + # # markup: rdoc + # # Class comment can go here + # + # class C + # end + # + # The comment should appear as the first line of the +content+. + # + # If the content contains a shebang or editor modeline the comment may + # appear on the second or third line. + # + # Any comment style may be used to hide the markup comment. + + def self.use_markup content + markup = content.lines.first(3).grep(/markup:\s+(\w+)/) { $1 }.first + + return unless markup + + # TODO Ruby should be returned only when the filename is correct + return RDoc::Parser::Ruby if %w[tomdoc markdown].include? markup + + markup = Regexp.escape markup + + _, selected = RDoc::Parser.parsers.find do |_, parser| + /^#{markup}$/i =~ parser.name.sub(/.*:/, '') + end + + selected + end + + ## + # Creates a new Parser storing +top_level+, +file_name+, +content+, + # +options+ and +stats+ in instance variables. In +@preprocess+ an + # RDoc::Markup::PreProcess object is created which allows processing of + # directives. + + def initialize top_level, file_name, content, options, stats + @top_level = top_level + @top_level.parser = self.class + @store = @top_level.store + + @file_name = file_name + @content = content + @options = options + @stats = stats + + @preprocess = RDoc::Markup::PreProcess.new @file_name, @options.rdoc_include + @preprocess.options = @options + end + + autoload :RubyTools, 'rdoc/parser/ruby_tools' + autoload :Text, 'rdoc/parser/text' + +end + +# simple must come first in order to show up last in the parsers list +require 'rdoc/parser/simple' +require 'rdoc/parser/c' +require 'rdoc/parser/changelog' +require 'rdoc/parser/markdown' +require 'rdoc/parser/rd' +require 'rdoc/parser/ruby' + diff --git a/jni/ruby/lib/rdoc/parser/c.rb b/jni/ruby/lib/rdoc/parser/c.rb new file mode 100644 index 0000000..fd336f5 --- /dev/null +++ b/jni/ruby/lib/rdoc/parser/c.rb @@ -0,0 +1,1229 @@ +require 'tsort' + +## +# RDoc::Parser::C attempts to parse C extension files. It looks for +# the standard patterns that you find in extensions: <tt>rb_define_class, +# rb_define_method</tt> and so on. It tries to find the corresponding +# C source for the methods and extract comments, but if we fail +# we don't worry too much. +# +# The comments associated with a Ruby method are extracted from the C +# comment block associated with the routine that _implements_ that +# method, that is to say the method whose name is given in the +# <tt>rb_define_method</tt> call. For example, you might write: +# +# /* +# * Returns a new array that is a one-dimensional flattening of this +# * array (recursively). That is, for every element that is an array, +# * extract its elements into the new array. +# * +# * s = [ 1, 2, 3 ] #=> [1, 2, 3] +# * t = [ 4, 5, 6, [7, 8] ] #=> [4, 5, 6, [7, 8]] +# * a = [ s, t, 9, 10 ] #=> [[1, 2, 3], [4, 5, 6, [7, 8]], 9, 10] +# * a.flatten #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] +# */ +# static VALUE +# rb_ary_flatten(ary) +# VALUE ary; +# { +# ary = rb_obj_dup(ary); +# rb_ary_flatten_bang(ary); +# return ary; +# } +# +# ... +# +# void +# Init_Array() +# { +# ... +# rb_define_method(rb_cArray, "flatten", rb_ary_flatten, 0); +# +# Here RDoc will determine from the rb_define_method line that there's a +# method called "flatten" in class Array, and will look for the implementation +# in the method rb_ary_flatten. It will then use the comment from that +# method in the HTML output. This method must be in the same source file +# as the rb_define_method. +# +# The comment blocks may include special directives: +# +# [Document-class: +name+] +# Documentation for the named class. +# +# [Document-module: +name+] +# Documentation for the named module. +# +# [Document-const: +name+] +# Documentation for the named +rb_define_const+. +# +# Constant values can be supplied on the first line of the comment like so: +# +# /* 300: The highest possible score in bowling */ +# rb_define_const(cFoo, "PERFECT", INT2FIX(300)); +# +# The value can contain internal colons so long as they are escaped with a \ +# +# [Document-global: +name+] +# Documentation for the named +rb_define_global_const+ +# +# [Document-variable: +name+] +# Documentation for the named +rb_define_variable+ +# +# [Document-method: +method_name+] +# Documentation for the named method. Use this when the method name is +# unambiguous. +# +# [Document-method: <tt>ClassName::method_name<tt>] +# Documentation for a singleton method in the given class. Use this when +# the method name alone is ambiguous. +# +# [Document-method: <tt>ClassName#method_name<tt>] +# Documentation for a instance method in the given class. Use this when the +# method name alone is ambiguous. +# +# [Document-attr: +name+] +# Documentation for the named attribute. +# +# [call-seq: <i>text up to an empty line</i>] +# Because C source doesn't give descriptive names to Ruby-level parameters, +# you need to document the calling sequence explicitly +# +# In addition, RDoc assumes by default that the C method implementing a +# Ruby function is in the same source file as the rb_define_method call. +# If this isn't the case, add the comment: +# +# rb_define_method(....); // in filename +# +# As an example, we might have an extension that defines multiple classes +# in its Init_xxx method. We could document them using +# +# /* +# * Document-class: MyClass +# * +# * Encapsulate the writing and reading of the configuration +# * file. ... +# */ +# +# /* +# * Document-method: read_value +# * +# * call-seq: +# * cfg.read_value(key) -> value +# * cfg.read_value(key} { |key| } -> value +# * +# * Return the value corresponding to +key+ from the configuration. +# * In the second form, if the key isn't found, invoke the +# * block and return its value. +# */ + +class RDoc::Parser::C < RDoc::Parser + + parse_files_matching(/\.(?:([CcHh])\1?|c([+xp])\2|y)\z/) + + include RDoc::Text + + ## + # Maps C variable names to names of Ruby classes or modules + + attr_reader :classes + + ## + # C file the parser is parsing + + attr_accessor :content + + ## + # Dependencies from a missing enclosing class to the classes in + # missing_dependencies that depend upon it. + + attr_reader :enclosure_dependencies + + ## + # Maps C variable names to names of Ruby classes (and singleton classes) + + attr_reader :known_classes + + ## + # Classes found while parsing the C file that were not yet registered due to + # a missing enclosing class. These are processed by do_missing + + attr_reader :missing_dependencies + + ## + # Maps C variable names to names of Ruby singleton classes + + attr_reader :singleton_classes + + ## + # The TopLevel items in the parsed file belong to + + attr_reader :top_level + + ## + # Prepares for parsing a C file. See RDoc::Parser#initialize for details on + # the arguments. + + def initialize top_level, file_name, content, options, stats + super + + @known_classes = RDoc::KNOWN_CLASSES.dup + @content = handle_tab_width handle_ifdefs_in @content + @file_dir = File.dirname @file_name + + @classes = load_variable_map :c_class_variables + @singleton_classes = load_variable_map :c_singleton_class_variables + + # class_variable => { function => [method, ...] } + @methods = Hash.new { |h, f| h[f] = Hash.new { |i, m| i[m] = [] } } + + # missing variable => [handle_class_module arguments] + @missing_dependencies = {} + + # missing enclosure variable => [dependent handle_class_module arguments] + @enclosure_dependencies = Hash.new { |h, k| h[k] = [] } + @enclosure_dependencies.instance_variable_set :@missing_dependencies, + @missing_dependencies + + @enclosure_dependencies.extend TSort + + def @enclosure_dependencies.tsort_each_node &block + each_key(&block) + rescue TSort::Cyclic => e + cycle_vars = e.message.scan(/"(.*?)"/).flatten + + cycle = cycle_vars.sort.map do |var_name| + delete var_name + + var_name, type, mod_name, = @missing_dependencies[var_name] + + "#{type} #{mod_name} (#{var_name})" + end.join ', ' + + warn "Unable to create #{cycle} due to a cyclic class or module creation" + + retry + end + + def @enclosure_dependencies.tsort_each_child node, &block + fetch(node, []).each(&block) + end + end + + ## + # Removes duplicate call-seq entries for methods using the same + # implementation. + + def deduplicate_call_seq + @methods.each do |var_name, functions| + class_name = @known_classes[var_name] + class_obj = find_class var_name, class_name + + functions.each_value do |method_names| + next if method_names.length == 1 + + method_names.each do |method_name| + deduplicate_method_name class_obj, method_name + end + end + end + end + + ## + # If two ruby methods share a C implementation (and comment) this + # deduplicates the examples in the call_seq for the method to reduce + # confusion in the output. + + def deduplicate_method_name class_obj, method_name # :nodoc: + return unless + method = class_obj.method_list.find { |m| m.name == method_name } + return unless call_seq = method.call_seq + + method_name = method_name[0, 1] if method_name =~ /\A\[/ + + entries = call_seq.split "\n" + + matching = entries.select do |entry| + entry =~ /^\w*\.?#{Regexp.escape method_name}/ or + entry =~ /\s#{Regexp.escape method_name}\s/ + end + + method.call_seq = matching.join "\n" + end + + ## + # Scans #content for rb_define_alias + + def do_aliases + @content.scan(/rb_define_alias\s*\( + \s*(\w+), + \s*"(.+?)", + \s*"(.+?)" + \s*\)/xm) do |var_name, new_name, old_name| + class_name = @known_classes[var_name] + + unless class_name then + @options.warn "Enclosing class or module %p for alias %s %s is not known" % [ + var_name, new_name, old_name] + next + end + + class_obj = find_class var_name, class_name + + al = RDoc::Alias.new '', old_name, new_name, '' + al.singleton = @singleton_classes.key? var_name + + comment = find_alias_comment var_name, new_name, old_name + + comment.normalize + + al.comment = comment + + al.record_location @top_level + + class_obj.add_alias al + @stats.add_alias al + end + end + + ## + # Scans #content for rb_attr and rb_define_attr + + def do_attrs + @content.scan(/rb_attr\s*\( + \s*(\w+), + \s*([\w"()]+), + \s*([01]), + \s*([01]), + \s*\w+\);/xm) do |var_name, attr_name, read, write| + handle_attr var_name, attr_name, read, write + end + + @content.scan(%r%rb_define_attr\( + \s*([\w\.]+), + \s*"([^"]+)", + \s*(\d+), + \s*(\d+)\s*\); + %xm) do |var_name, attr_name, read, write| + handle_attr var_name, attr_name, read, write + end + end + + ## + # Scans #content for boot_defclass + + def do_boot_defclass + @content.scan(/(\w+)\s*=\s*boot_defclass\s*\(\s*"(\w+?)",\s*(\w+?)\s*\)/) do + |var_name, class_name, parent| + parent = nil if parent == "0" + handle_class_module(var_name, :class, class_name, parent, nil) + end + end + + ## + # Scans #content for rb_define_class, boot_defclass, rb_define_class_under + # and rb_singleton_class + + def do_classes + do_boot_defclass + do_define_class + do_define_class_under + do_singleton_class + do_struct_define_without_accessor + end + + ## + # Scans #content for rb_define_variable, rb_define_readonly_variable, + # rb_define_const and rb_define_global_const + + def do_constants + @content.scan(%r%\Wrb_define_ + ( variable | + readonly_variable | + const | + global_const ) + \s*\( + (?:\s*(\w+),)? + \s*"(\w+)", + \s*(.*?)\s*\)\s*; + %xm) do |type, var_name, const_name, definition| + var_name = "rb_cObject" if !var_name or var_name == "rb_mKernel" + handle_constants type, var_name, const_name, definition + end + + @content.scan(%r% + \Wrb_curses_define_const + \s*\( + \s* + (\w+) + \s* + \) + \s*;%xm) do |consts| + const = consts.first + + handle_constants 'const', 'mCurses', const, "UINT2NUM(#{const})" + end + + @content.scan(%r% + \Wrb_file_const + \s*\( + \s* + "([^"]+)", + \s* + (.*?) + \s* + \) + \s*;%xm) do |name, value| + handle_constants 'const', 'rb_mFConst', name, value + end + end + + ## + # Scans #content for rb_define_class + + def do_define_class + # The '.' lets us handle SWIG-generated files + @content.scan(/([\w\.]+)\s* = \s*rb_define_class\s* + \( + \s*"(\w+)", + \s*(\w+)\s* + \)/mx) do |var_name, class_name, parent| + handle_class_module(var_name, :class, class_name, parent, nil) + end + end + + ## + # Scans #content for rb_define_class_under + + def do_define_class_under + @content.scan(/([\w\.]+)\s* = # var_name + \s*rb_define_class_under\s* + \( + \s* (\w+), # under + \s* "(\w+)", # class_name + \s* + (?: + ([\w\*\s\(\)\.\->]+) | # parent_name + rb_path2class\("([\w:]+)"\) # path + ) + \s* + \) + /mx) do |var_name, under, class_name, parent_name, path| + parent = path || parent_name + + handle_class_module var_name, :class, class_name, parent, under + end + end + + ## + # Scans #content for rb_define_module + + def do_define_module + @content.scan(/(\w+)\s* = \s*rb_define_module\s*\(\s*"(\w+)"\s*\)/mx) do + |var_name, class_name| + handle_class_module(var_name, :module, class_name, nil, nil) + end + end + + ## + # Scans #content for rb_define_module_under + + def do_define_module_under + @content.scan(/(\w+)\s* = \s*rb_define_module_under\s* + \( + \s*(\w+), + \s*"(\w+)" + \s*\)/mx) do |var_name, in_module, class_name| + handle_class_module(var_name, :module, class_name, nil, in_module) + end + end + + ## + # Scans #content for rb_include_module + + def do_includes + @content.scan(/rb_include_module\s*\(\s*(\w+?),\s*(\w+?)\s*\)/) do |c,m| + next unless cls = @classes[c] + m = @known_classes[m] || m + + comment = RDoc::Comment.new '', @top_level + incl = cls.add_include RDoc::Include.new(m, comment) + incl.record_location @top_level + end + end + + ## + # Scans #content for rb_define_method, rb_define_singleton_method, + # rb_define_module_function, rb_define_private_method, + # rb_define_global_function and define_filetest_function + + def do_methods + @content.scan(%r%rb_define_ + ( + singleton_method | + method | + module_function | + private_method + ) + \s*\(\s*([\w\.]+), + \s*"([^"]+)", + \s*(?:RUBY_METHOD_FUNC\(|VALUEFUNC\(|\(METHOD\))?(\w+)\)?, + \s*(-?\w+)\s*\) + (?:;\s*/[*/]\s+in\s+(\w+?\.(?:cpp|c|y)))? + %xm) do |type, var_name, meth_name, function, param_count, source_file| + + # Ignore top-object and weird struct.c dynamic stuff + next if var_name == "ruby_top_self" + next if var_name == "nstr" + + var_name = "rb_cObject" if var_name == "rb_mKernel" + handle_method(type, var_name, meth_name, function, param_count, + source_file) + end + + @content.scan(%r%rb_define_global_function\s*\( + \s*"([^"]+)", + \s*(?:RUBY_METHOD_FUNC\(|VALUEFUNC\()?(\w+)\)?, + \s*(-?\w+)\s*\) + (?:;\s*/[*/]\s+in\s+(\w+?\.[cy]))? + %xm) do |meth_name, function, param_count, source_file| + handle_method("method", "rb_mKernel", meth_name, function, param_count, + source_file) + end + + @content.scan(/define_filetest_function\s*\( + \s*"([^"]+)", + \s*(?:RUBY_METHOD_FUNC\(|VALUEFUNC\()?(\w+)\)?, + \s*(-?\w+)\s*\)/xm) do |meth_name, function, param_count| + + handle_method("method", "rb_mFileTest", meth_name, function, param_count) + handle_method("singleton_method", "rb_cFile", meth_name, function, + param_count) + end + end + + ## + # Creates classes and module that were missing were defined due to the file + # order being different than the declaration order. + + def do_missing + return if @missing_dependencies.empty? + + @enclosure_dependencies.tsort.each do |in_module| + arguments = @missing_dependencies.delete in_module + + next unless arguments # dependency on existing class + + handle_class_module(*arguments) + end + end + + ## + # Scans #content for rb_define_module and rb_define_module_under + + def do_modules + do_define_module + do_define_module_under + end + + ## + # Scans #content for rb_singleton_class + + def do_singleton_class + @content.scan(/([\w\.]+)\s* = \s*rb_singleton_class\s* + \( + \s*(\w+) + \s*\)/mx) do |sclass_var, class_var| + handle_singleton sclass_var, class_var + end + end + + ## + # Scans #content for struct_define_without_accessor + + def do_struct_define_without_accessor + @content.scan(/([\w\.]+)\s* = \s*rb_struct_define_without_accessor\s* + \( + \s*"(\w+)", # Class name + \s*(\w+), # Parent class + \s*\w+, # Allocation function + (\s*"\w+",)* # Attributes + \s*NULL + \)/mx) do |var_name, class_name, parent| + handle_class_module(var_name, :class, class_name, parent, nil) + end + end + + ## + # Finds the comment for an alias on +class_name+ from +new_name+ to + # +old_name+ + + def find_alias_comment class_name, new_name, old_name + content =~ %r%((?>/\*.*?\*/\s+)) + rb_define_alias\(\s*#{Regexp.escape class_name}\s*, + \s*"#{Regexp.escape new_name}"\s*, + \s*"#{Regexp.escape old_name}"\s*\);%xm + + RDoc::Comment.new($1 || '', @top_level) + end + + ## + # Finds a comment for rb_define_attr, rb_attr or Document-attr. + # + # +var_name+ is the C class variable the attribute is defined on. + # +attr_name+ is the attribute's name. + # + # +read+ and +write+ are the read/write flags ('1' or '0'). Either both or + # neither must be provided. + + def find_attr_comment var_name, attr_name, read = nil, write = nil + attr_name = Regexp.escape attr_name + + rw = if read and write then + /\s*#{read}\s*,\s*#{write}\s*/xm + else + /.*?/m + end + + comment = if @content =~ %r%((?>/\*.*?\*/\s+)) + rb_define_attr\((?:\s*#{var_name},)?\s* + "#{attr_name}"\s*, + #{rw}\)\s*;%xm then + $1 + elsif @content =~ %r%((?>/\*.*?\*/\s+)) + rb_attr\(\s*#{var_name}\s*, + \s*#{attr_name}\s*, + #{rw},.*?\)\s*;%xm then + $1 + elsif @content =~ %r%(/\*.*?(?:\s*\*\s*)?) + Document-attr:\s#{attr_name}\s*?\n + ((?>(.|\n)*?\*/))%x then + "#{$1}\n#{$2}" + else + '' + end + + RDoc::Comment.new comment, @top_level + end + + ## + # Find the C code corresponding to a Ruby method + + def find_body class_name, meth_name, meth_obj, file_content, quiet = false + case file_content + when %r%((?>/\*.*?\*/\s*)?) + ((?:(?:\w+)\s+)? + (?:intern\s+)?VALUE\s+#{meth_name} + \s*(\([^)]*\))([^;]|$))%xm then + comment = RDoc::Comment.new $1, @top_level + body = $2 + offset, = $~.offset(2) + + comment.remove_private if comment + + # try to find the whole body + body = $& if /#{Regexp.escape body}[^(]*?\{.*?^\}/m =~ file_content + + # The comment block may have been overridden with a 'Document-method' + # block. This happens in the interpreter when multiple methods are + # vectored through to the same C method but those methods are logically + # distinct (for example Kernel.hash and Kernel.object_id share the same + # implementation + + override_comment = find_override_comment class_name, meth_obj + comment = override_comment if override_comment + + comment.normalize + find_modifiers comment, meth_obj if comment + + #meth_obj.params = params + meth_obj.start_collecting_tokens + tk = RDoc::RubyToken::Token.new nil, 1, 1 + tk.set_text body + meth_obj.add_token tk + meth_obj.comment = comment + meth_obj.offset = offset + meth_obj.line = file_content[0, offset].count("\n") + 1 + + body + when %r%((?>/\*.*?\*/\s*))^\s*(\#\s*define\s+#{meth_name}\s+(\w+))%m then + comment = RDoc::Comment.new $1, @top_level + body = $2 + offset = $~.offset(2).first + + find_body class_name, $3, meth_obj, file_content, true + + comment.normalize + find_modifiers comment, meth_obj + + meth_obj.start_collecting_tokens + tk = RDoc::RubyToken::Token.new nil, 1, 1 + tk.set_text body + meth_obj.add_token tk + meth_obj.comment = comment + meth_obj.offset = offset + meth_obj.line = file_content[0, offset].count("\n") + 1 + + body + when %r%^\s*\#\s*define\s+#{meth_name}\s+(\w+)%m then + # with no comment we hope the aliased definition has it and use it's + # definition + + body = find_body(class_name, $1, meth_obj, file_content, true) + + return body if body + + @options.warn "No definition for #{meth_name}" + false + else # No body, but might still have an override comment + comment = find_override_comment class_name, meth_obj + + if comment then + comment.normalize + find_modifiers comment, meth_obj + meth_obj.comment = comment + + '' + else + @options.warn "No definition for #{meth_name}" + false + end + end + end + + ## + # Finds a RDoc::NormalClass or RDoc::NormalModule for +raw_name+ + + def find_class(raw_name, name) + unless @classes[raw_name] + if raw_name =~ /^rb_m/ + container = @top_level.add_module RDoc::NormalModule, name + else + container = @top_level.add_class RDoc::NormalClass, name + end + + container.record_location @top_level + @classes[raw_name] = container + end + @classes[raw_name] + end + + ## + # Look for class or module documentation above Init_+class_name+(void), + # in a Document-class +class_name+ (or module) comment or above an + # rb_define_class (or module). If a comment is supplied above a matching + # Init_ and a rb_define_class the Init_ comment is used. + # + # /* + # * This is a comment for Foo + # */ + # Init_Foo(void) { + # VALUE cFoo = rb_define_class("Foo", rb_cObject); + # } + # + # /* + # * Document-class: Foo + # * This is a comment for Foo + # */ + # Init_foo(void) { + # VALUE cFoo = rb_define_class("Foo", rb_cObject); + # } + # + # /* + # * This is a comment for Foo + # */ + # VALUE cFoo = rb_define_class("Foo", rb_cObject); + + def find_class_comment class_name, class_mod + comment = nil + + if @content =~ %r% + ((?>/\*.*?\*/\s+)) + (static\s+)? + void\s+ + Init_#{class_name}\s*(?:_\(\s*)?\(\s*(?:void\s*)?\)%xmi then + comment = $1.sub(%r%Document-(?:class|module):\s+#{class_name}%, '') + elsif @content =~ %r%Document-(?:class|module):\s+#{class_name}\s*? + (?:<\s+[:,\w]+)?\n((?>.*?\*/))%xm then + comment = "/*\n#{$1}" + elsif @content =~ %r%((?>/\*.*?\*/\s+)) + ([\w\.\s]+\s* = \s+)?rb_define_(class|module)[\t (]*?"(#{class_name})"%xm then + comment = $1 + elsif @content =~ %r%((?>/\*.*?\*/\s+)) + ([\w\. \t]+ = \s+)?rb_define_(class|module)_under[\t\w, (]*?"(#{class_name.split('::').last})"%xm then + comment = $1 + else + comment = '' + end + + comment = RDoc::Comment.new comment, @top_level + comment.normalize + + look_for_directives_in class_mod, comment + + class_mod.add_comment comment, @top_level + end + + ## + # Finds a comment matching +type+ and +const_name+ either above the + # comment or in the matching Document- section. + + def find_const_comment(type, const_name, class_name = nil) + comment = if @content =~ %r%((?>^\s*/\*.*?\*/\s+)) + rb_define_#{type}\((?:\s*(\w+),)?\s* + "#{const_name}"\s*, + .*?\)\s*;%xmi then + $1 + elsif class_name and + @content =~ %r%Document-(?:const|global|variable):\s + #{class_name}::#{const_name} + \s*?\n((?>.*?\*/))%xm then + "/*\n#{$1}" + elsif @content =~ %r%Document-(?:const|global|variable): + \s#{const_name} + \s*?\n((?>.*?\*/))%xm then + "/*\n#{$1}" + else + '' + end + + RDoc::Comment.new comment, @top_level + end + + ## + # Handles modifiers in +comment+ and updates +meth_obj+ as appropriate. + + def find_modifiers comment, meth_obj + comment.normalize + comment.extract_call_seq meth_obj + + look_for_directives_in meth_obj, comment + end + + ## + # Finds a <tt>Document-method</tt> override for +meth_obj+ on +class_name+ + + def find_override_comment class_name, meth_obj + name = Regexp.escape meth_obj.name + prefix = Regexp.escape meth_obj.name_prefix + + comment = if @content =~ %r%Document-method: + \s+#{class_name}#{prefix}#{name} + \s*?\n((?>.*?\*/))%xm then + "/*#{$1}" + elsif @content =~ %r%Document-method: + \s#{name}\s*?\n((?>.*?\*/))%xm then + "/*#{$1}" + end + + return unless comment + + RDoc::Comment.new comment, @top_level + end + + ## + # Creates a new RDoc::Attr +attr_name+ on class +var_name+ that is either + # +read+, +write+ or both + + def handle_attr(var_name, attr_name, read, write) + rw = '' + rw << 'R' if '1' == read + rw << 'W' if '1' == write + + class_name = @known_classes[var_name] + + return unless class_name + + class_obj = find_class var_name, class_name + + return unless class_obj + + comment = find_attr_comment var_name, attr_name + comment.normalize + + name = attr_name.gsub(/rb_intern\("([^"]+)"\)/, '\1') + + attr = RDoc::Attr.new '', name, rw, comment + + attr.record_location @top_level + class_obj.add_attribute attr + @stats.add_attribute attr + end + + ## + # Creates a new RDoc::NormalClass or RDoc::NormalModule based on +type+ + # named +class_name+ in +parent+ which was assigned to the C +var_name+. + + def handle_class_module(var_name, type, class_name, parent, in_module) + parent_name = @known_classes[parent] || parent + + if in_module then + enclosure = @classes[in_module] || @store.find_c_enclosure(in_module) + + if enclosure.nil? and enclosure = @known_classes[in_module] then + enc_type = /^rb_m/ =~ in_module ? :module : :class + handle_class_module in_module, enc_type, enclosure, nil, nil + enclosure = @classes[in_module] + end + + unless enclosure then + @enclosure_dependencies[in_module] << var_name + @missing_dependencies[var_name] = + [var_name, type, class_name, parent, in_module] + + return + end + else + enclosure = @top_level + end + + if type == :class then + full_name = if RDoc::ClassModule === enclosure then + enclosure.full_name + "::#{class_name}" + else + class_name + end + + 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 + else + cm = enclosure.add_module RDoc::NormalModule, class_name + end + + cm.record_location enclosure.top_level + + find_class_comment cm.full_name, cm + + case cm + when RDoc::NormalClass + @stats.add_class cm + when RDoc::NormalModule + @stats.add_module cm + end + + @classes[var_name] = cm + @known_classes[var_name] = cm.full_name + @store.add_c_enclosure var_name, cm + end + + ## + # Adds constants. By providing some_value: at the start of the comment you + # can override the C value of the comment to give a friendly definition. + # + # /* 300: The perfect score in bowling */ + # rb_define_const(cFoo, "PERFECT", INT2FIX(300); + # + # Will override <tt>INT2FIX(300)</tt> with the value +300+ in the output + # RDoc. Values may include quotes and escaped colons (\:). + + def handle_constants(type, var_name, const_name, definition) + class_name = @known_classes[var_name] + + return unless class_name + + class_obj = find_class var_name, class_name + + unless class_obj then + @options.warn 'Enclosing class or module %p is not known' % [const_name] + return + end + + comment = find_const_comment type, const_name, class_name + comment.normalize + + # In the case of rb_define_const, the definition and comment are in + # "/* definition: comment */" form. The literal ':' and '\' characters + # can be escaped with a backslash. + if type.downcase == 'const' then + no_match, new_definition, new_comment = comment.text.split(/(\A.*):/) + + if no_match and no_match.empty? then + if new_definition.empty? then # Default to literal C definition + new_definition = definition + else + new_definition.gsub!("\:", ":") + new_definition.gsub!("\\", '\\') + end + + new_definition.sub!(/\A(\s+)/, '') + + new_comment = "#{$1}#{new_comment.lstrip}" + + new_comment = RDoc::Comment.new new_comment, @top_level + + con = RDoc::Constant.new const_name, new_definition, new_comment + else + con = RDoc::Constant.new const_name, definition, comment + end + else + con = RDoc::Constant.new const_name, definition, comment + end + + con.record_location @top_level + @stats.add_constant con + class_obj.add_constant con + end + + ## + # Removes #ifdefs that would otherwise confuse us + + def handle_ifdefs_in(body) + body.gsub(/^#ifdef HAVE_PROTOTYPES.*?#else.*?\n(.*?)#endif.*?\n/m, '\1') + end + + ## + # Adds an RDoc::AnyMethod +meth_name+ defined on a class or module assigned + # to +var_name+. +type+ is the type of method definition function used. + # +singleton_method+ and +module_function+ create a singleton method. + + def handle_method(type, var_name, meth_name, function, param_count, + source_file = nil) + class_name = @known_classes[var_name] + singleton = @singleton_classes.key? var_name + + @methods[var_name][function] << meth_name + + return unless class_name + + class_obj = find_class var_name, class_name + + if class_obj then + if meth_name == 'initialize' then + meth_name = 'new' + singleton = true + type = 'method' # force public + end + + meth_obj = RDoc::AnyMethod.new '', meth_name + meth_obj.c_function = function + meth_obj.singleton = + singleton || %w[singleton_method module_function].include?(type) + + p_count = Integer(param_count) rescue -1 + + if source_file then + file_name = File.join @file_dir, source_file + + if File.exist? file_name then + file_content = File.read file_name + else + @options.warn "unknown source #{source_file} for #{meth_name} in #{@file_name}" + end + else + file_content = @content + end + + body = find_body class_name, function, meth_obj, file_content + + if body and meth_obj.document_self then + meth_obj.params = if p_count < -1 then # -2 is Array + '(*args)' + elsif p_count == -1 then # argc, argv + rb_scan_args body + else + "(#{(1..p_count).map { |i| "p#{i}" }.join ', '})" + end + + + meth_obj.record_location @top_level + class_obj.add_method meth_obj + @stats.add_method meth_obj + meth_obj.visibility = :private if 'private_method' == type + end + end + end + + ## + # Registers a singleton class +sclass_var+ as a singleton of +class_var+ + + def handle_singleton sclass_var, class_var + class_name = @known_classes[class_var] + + @known_classes[sclass_var] = class_name + @singleton_classes[sclass_var] = class_name + end + + ## + # Normalizes tabs in +body+ + + def handle_tab_width(body) + if /\t/ =~ body + tab_width = @options.tab_width + body.split(/\n/).map do |line| + 1 while line.gsub!(/\t+/) do + ' ' * (tab_width * $&.length - $`.length % tab_width) + end && $~ + line + end.join "\n" + else + body + end + end + + ## + # Loads the variable map with the given +name+ from the RDoc::Store, if + # present. + + def load_variable_map map_name + return {} unless files = @store.cache[map_name] + return {} unless name_map = files[@file_name] + + class_map = {} + + name_map.each do |variable, name| + next unless mod = @store.find_class_or_module(name) + + class_map[variable] = if map_name == :c_class_variables then + mod + else + name + end + @known_classes[variable] = name + end + + class_map + end + + ## + # Look for directives in a normal comment block: + # + # /* + # * :title: My Awesome Project + # */ + # + # This method modifies the +comment+ + + def look_for_directives_in context, comment + @preprocess.handle comment, context do |directive, param| + case directive + when 'main' then + @options.main_page = param + '' + when 'title' then + @options.default_title = param if @options.respond_to? :default_title= + '' + end + end + + comment + end + + ## + # Extracts parameters from the +method_body+ and returns a method + # parameter string. Follows 1.9.3dev's scan-arg-spec, see README.EXT + + def rb_scan_args method_body + method_body =~ /rb_scan_args\((.*?)\)/m + return '(*args)' unless $1 + + $1.split(/,/)[2] =~ /"(.*?)"/ # format argument + format = $1.split(//) + + lead = opt = trail = 0 + + if format.first =~ /\d/ then + lead = $&.to_i + format.shift + if format.first =~ /\d/ then + opt = $&.to_i + format.shift + if format.first =~ /\d/ then + trail = $&.to_i + format.shift + block_arg = true + end + end + end + + if format.first == '*' and not block_arg then + var = true + format.shift + if format.first =~ /\d/ then + trail = $&.to_i + format.shift + end + end + + if format.first == ':' then + hash = true + format.shift + end + + if format.first == '&' then + block = true + format.shift + end + + # if the format string is not empty there's a bug in the C code, ignore it + + args = [] + position = 1 + + (1...(position + lead)).each do |index| + args << "p#{index}" + end + + position += lead + + (position...(position + opt)).each do |index| + args << "p#{index} = v#{index}" + end + + position += opt + + if var then + args << '*args' + position += 1 + end + + (position...(position + trail)).each do |index| + args << "p#{index}" + end + + position += trail + + if hash then + args << "p#{position} = {}" + end + + args << '&block' if block + + "(#{args.join ', '})" + end + + ## + # Removes lines that are commented out that might otherwise get picked up + # when scanning for classes and methods + + def remove_commented_out_lines + @content.gsub!(%r%//.*rb_define_%, '//') + end + + ## + # Extracts the classes, modules, methods, attributes, constants and aliases + # from a C file and returns an RDoc::TopLevel for this file + + def scan + remove_commented_out_lines + + do_modules + do_classes + do_missing + + do_constants + do_methods + do_includes + do_aliases + do_attrs + + deduplicate_call_seq + + @store.add_c_variables self + + @top_level + end + +end + diff --git a/jni/ruby/lib/rdoc/parser/changelog.rb b/jni/ruby/lib/rdoc/parser/changelog.rb new file mode 100644 index 0000000..a3567c1 --- /dev/null +++ b/jni/ruby/lib/rdoc/parser/changelog.rb @@ -0,0 +1,198 @@ +require 'time' + +## +# A ChangeLog file parser. +# +# This parser converts a ChangeLog into an RDoc::Markup::Document. When +# viewed as HTML a ChangeLog page will have an entry for each day's entries in +# the sidebar table of contents. +# +# This parser is meant to parse the MRI ChangeLog, but can be used to parse any +# {GNU style Change +# Log}[http://www.gnu.org/prep/standards/html_node/Style-of-Change-Logs.html]. + +class RDoc::Parser::ChangeLog < RDoc::Parser + + include RDoc::Parser::Text + + parse_files_matching(/(\/|\\|\A)ChangeLog[^\/\\]*\z/) + + ## + # Attaches the +continuation+ of the previous line to the +entry_body+. + # + # Continued function listings are joined together as a single entry. + # Continued descriptions are joined to make a single paragraph. + + def continue_entry_body entry_body, continuation + return unless last = entry_body.last + + if last =~ /\)\s*\z/ and continuation =~ /\A\(/ then + last.sub!(/\)\s*\z/, ',') + continuation.sub!(/\A\(/, '') + end + + if last =~ /\s\z/ then + last << continuation + else + last << ' ' << continuation + end + end + + ## + # Creates an RDoc::Markup::Document given the +groups+ of ChangeLog entries. + + def create_document groups + doc = RDoc::Markup::Document.new + doc.omit_headings_below = 2 + doc.file = @top_level + + doc << RDoc::Markup::Heading.new(1, File.basename(@file_name)) + doc << RDoc::Markup::BlankLine.new + + groups.sort_by do |day,| day end.reverse_each do |day, entries| + doc << RDoc::Markup::Heading.new(2, day.dup) + doc << RDoc::Markup::BlankLine.new + + doc.concat create_entries entries + end + + doc + end + + ## + # Returns a list of ChangeLog entries an RDoc::Markup nodes for the given + # +entries+. + + def create_entries entries + out = [] + + entries.each do |entry, items| + out << RDoc::Markup::Heading.new(3, entry) + out << RDoc::Markup::BlankLine.new + + out << create_items(items) + end + + out + end + + ## + # Returns an RDoc::Markup::List containing the given +items+ in the + # ChangeLog + + def create_items items + list = RDoc::Markup::List.new :NOTE + + items.each do |item| + item =~ /\A(.*?(?:\([^)]+\))?):\s*/ + + title = $1 + body = $' + + paragraph = RDoc::Markup::Paragraph.new body + list_item = RDoc::Markup::ListItem.new title, paragraph + list << list_item + end + + list + end + + ## + # Groups +entries+ by date. + + def group_entries entries + entries.group_by do |title, _| + begin + Time.parse(title).strftime '%Y-%m-%d' + rescue NoMethodError, ArgumentError + time, = title.split ' ', 2 + Time.parse(time).strftime '%Y-%m-%d' + end + end + end + + ## + # Parses the entries in the ChangeLog. + # + # Returns an Array of each ChangeLog entry in order of parsing. + # + # A ChangeLog entry is an Array containing the ChangeLog title (date and + # committer) and an Array of ChangeLog items (file and function changed with + # description). + # + # An example result would be: + # + # [ 'Tue Dec 4 08:33:46 2012 Eric Hodel <drbrain@segment7.net>', + # [ 'README.EXT: Converted to RDoc format', + # 'README.EXT.ja: ditto']] + + def parse_entries + entries = [] + entry_name = nil + entry_body = [] + + @content.each_line do |line| + case line + when /^\s*$/ then + next + when /^\w.*/ then + entries << [entry_name, entry_body] if entry_name + + entry_name = $& + + begin + time = Time.parse entry_name + # HACK Ruby 1.8 does not raise ArgumentError for Time.parse "Other" + entry_name = nil unless entry_name =~ /#{time.year}/ + rescue NoMethodError + # HACK Ruby 2.1.2 and earlier raises NoMethodError if time part is absent + entry_name.split ' ', 2 + rescue ArgumentError + if /out of range/ =~ $!.message + Time.parse(entry_name.split(' ', 2)[0]) rescue entry_name = nil + else + entry_name = nil + end + end + + entry_body = [] + when /^(\t| {8})?\*\s*(.*)/ then # "\t* file.c (func): ..." + entry_body << $2 + when /^(\t| {8})?\s*(\(.*)/ then # "\t(func): ..." + entry = $2 + + if entry_body.last =~ /:/ then + entry_body << entry + else + continue_entry_body entry_body, entry + end + when /^(\t| {8})?\s*(.*)/ then + continue_entry_body entry_body, $2 + end + end + + entries << [entry_name, entry_body] if entry_name + + entries.reject! do |(entry,_)| + entry == nil + end + + entries + end + + ## + # Converts the ChangeLog into an RDoc::Markup::Document + + def scan + entries = parse_entries + grouped_entries = group_entries entries + + doc = create_document grouped_entries + + @top_level.comment = doc + + @top_level + end + +end + diff --git a/jni/ruby/lib/rdoc/parser/markdown.rb b/jni/ruby/lib/rdoc/parser/markdown.rb new file mode 100644 index 0000000..6fd88cf --- /dev/null +++ b/jni/ruby/lib/rdoc/parser/markdown.rb @@ -0,0 +1,23 @@ +## +# Parse a Markdown format file. The parsed RDoc::Markup::Document is attached +# as a file comment. + +class RDoc::Parser::Markdown < RDoc::Parser + + include RDoc::Parser::Text + + parse_files_matching(/\.(md|markdown)(?:\.[^.]+)?$/) + + ## + # Creates an Markdown-format TopLevel for the given file. + + def scan + comment = RDoc::Comment.new @content, @top_level + comment.format = 'markdown' + + @top_level.comment = comment + end + +end + + diff --git a/jni/ruby/lib/rdoc/parser/rd.rb b/jni/ruby/lib/rdoc/parser/rd.rb new file mode 100644 index 0000000..09069ae --- /dev/null +++ b/jni/ruby/lib/rdoc/parser/rd.rb @@ -0,0 +1,22 @@ +## +# Parse a RD format file. The parsed RDoc::Markup::Document is attached as a +# file comment. + +class RDoc::Parser::RD < RDoc::Parser + + include RDoc::Parser::Text + + parse_files_matching(/\.rd(?:\.[^.]+)?$/) + + ## + # Creates an rd-format TopLevel for the given file. + + def scan + comment = RDoc::Comment.new @content, @top_level + comment.format = 'rd' + + @top_level.comment = comment + end + +end + diff --git a/jni/ruby/lib/rdoc/parser/ruby.rb b/jni/ruby/lib/rdoc/parser/ruby.rb new file mode 100644 index 0000000..ce1083e --- /dev/null +++ b/jni/ruby/lib/rdoc/parser/ruby.rb @@ -0,0 +1,2160 @@ +## +# This file contains stuff stolen outright from: +# +# rtags.rb - +# ruby-lex.rb - ruby lexcal analyzer +# ruby-token.rb - ruby tokens +# by Keiju ISHITSUKA (Nippon Rational Inc.) +# + +$TOKEN_DEBUG ||= nil + +## +# Extracts code elements from a source file returning a TopLevel object +# containing the constituent file elements. +# +# This file is based on rtags +# +# RubyParser understands how to document: +# * classes +# * modules +# * methods +# * constants +# * aliases +# * private, public, protected +# * private_class_function, public_class_function +# * module_function +# * attr, attr_reader, attr_writer, attr_accessor +# * extra accessors given on the command line +# * metaprogrammed methods +# * require +# * include +# +# == Method Arguments +# +#-- +# NOTE: I don't think this works, needs tests, remove the paragraph following +# this block when known to work +# +# The parser extracts the arguments from the method definition. You can +# override this with a custom argument definition using the :args: directive: +# +# ## +# # This method tries over and over until it is tired +# +# def go_go_go(thing_to_try, tries = 10) # :args: thing_to_try +# puts thing_to_try +# go_go_go thing_to_try, tries - 1 +# end +# +# If you have a more-complex set of overrides you can use the :call-seq: +# directive: +#++ +# +# The parser extracts the arguments from the method definition. You can +# override this with a custom argument definition using the :call-seq: +# directive: +# +# ## +# # This method can be called with a range or an offset and length +# # +# # :call-seq: +# # my_method(Range) +# # my_method(offset, length) +# +# def my_method(*args) +# end +# +# The parser extracts +yield+ expressions from method bodies to gather the +# yielded argument names. If your method manually calls a block instead of +# yielding or you want to override the discovered argument names use +# the :yields: directive: +# +# ## +# # My method is awesome +# +# def my_method(&block) # :yields: happy, times +# block.call 1, 2 +# end +# +# == Metaprogrammed Methods +# +# To pick up a metaprogrammed method, the parser looks for a comment starting +# with '##' before an identifier: +# +# ## +# # This is a meta-programmed method! +# +# add_my_method :meta_method, :arg1, :arg2 +# +# The parser looks at the token after the identifier to determine the name, in +# this example, :meta_method. If a name cannot be found, a warning is printed +# and 'unknown is used. +# +# You can force the name of a method using the :method: directive: +# +# ## +# # :method: some_method! +# +# By default, meta-methods are instance methods. To indicate that a method is +# a singleton method instead use the :singleton-method: directive: +# +# ## +# # :singleton-method: +# +# You can also use the :singleton-method: directive with a name: +# +# ## +# # :singleton-method: some_method! +# +# You can define arguments for metaprogrammed methods via either the +# :call-seq:, :arg: or :args: directives. +# +# Additionally you can mark a method as an attribute by +# using :attr:, :attr_reader:, :attr_writer: or :attr_accessor:. Just like +# for :method:, the name is optional. +# +# ## +# # :attr_reader: my_attr_name +# +# == Hidden methods and attributes +# +# You can provide documentation for methods that don't appear using +# the :method:, :singleton-method: and :attr: directives: +# +# ## +# # :attr_writer: ghost_writer +# # There is an attribute here, but you can't see it! +# +# ## +# # :method: ghost_method +# # There is a method here, but you can't see it! +# +# ## +# # this is a comment for a regular method +# +# def regular_method() end +# +# Note that by default, the :method: directive will be ignored if there is a +# standard rdocable item following it. + +class RDoc::Parser::Ruby < RDoc::Parser + + parse_files_matching(/\.rbw?$/) + + include RDoc::RubyToken + include RDoc::TokenStream + include RDoc::Parser::RubyTools + + ## + # RDoc::NormalClass type + + NORMAL = "::" + + ## + # RDoc::SingleClass type + + SINGLE = "<<" + + ## + # Creates a new Ruby parser. + + def initialize(top_level, file_name, content, options, stats) + super + + @size = 0 + @token_listeners = nil + @scanner = RDoc::RubyLex.new content, @options + @scanner.exception_on_syntax_error = false + @prev_seek = nil + @markup = @options.markup + @track_visibility = :nodoc != @options.visibility + + @encoding = nil + @encoding = @options.encoding if Object.const_defined? :Encoding + + reset + end + + ## + # Retrieves the read token stream and replaces +pattern+ with +replacement+ + # using gsub. If the result is only a ";" returns an empty string. + + def get_tkread_clean pattern, replacement # :nodoc: + read = get_tkread.gsub(pattern, replacement).strip + return '' if read == ';' + read + end + + ## + # Extracts the visibility information for the visibility token +tk+ + # and +single+ class type identifier. + # + # Returns the visibility type (a string), the visibility (a symbol) and + # +singleton+ if the methods following should be converted to singleton + # methods. + + def get_visibility_information tk, single # :nodoc: + vis_type = tk.name + singleton = single == SINGLE + + vis = + case vis_type + when 'private' then :private + when 'protected' then :protected + when 'public' then :public + when 'private_class_method' then + singleton = true + :private + when 'public_class_method' then + singleton = true + :public + when 'module_function' then + singleton = true + :public + else + raise RDoc::Error, "Invalid visibility: #{tk.name}" + end + + return vis_type, vis, singleton + end + + ## + # Look for the first comment in a file that isn't a shebang line. + + def collect_first_comment + skip_tkspace + comment = '' + comment.force_encoding @encoding if @encoding + first_line = true + first_comment_tk_class = nil + + tk = get_tk + + while TkCOMMENT === tk + if first_line and tk.text =~ /\A#!/ then + skip_tkspace + tk = get_tk + elsif first_line and tk.text =~ /\A#\s*-\*-/ then + first_line = false + skip_tkspace + tk = get_tk + else + break if first_comment_tk_class and not first_comment_tk_class === tk + first_comment_tk_class = tk.class + + first_line = false + comment << tk.text << "\n" + tk = get_tk + + if TkNL === tk then + skip_tkspace false + tk = get_tk + end + end + end + + unget_tk tk + + new_comment comment + end + + ## + # Consumes trailing whitespace from the token stream + + def consume_trailing_spaces # :nodoc: + get_tkread + skip_tkspace false + end + + ## + # Creates a new attribute in +container+ with +name+. + + def create_attr container, single, name, rw, comment # :nodoc: + att = RDoc::Attr.new get_tkread, name, rw, comment, single == SINGLE + record_location att + + container.add_attribute att + @stats.add_attribute att + + att + end + + ## + # Creates a module alias in +container+ at +rhs_name+ (or at the top-level + # for "::") with the name from +constant+. + + def create_module_alias container, constant, rhs_name # :nodoc: + mod = if rhs_name =~ /^::/ then + @store.find_class_or_module rhs_name + else + container.find_module_named rhs_name + end + + container.add_module_alias mod, constant.name, @top_level if mod + end + + ## + # Aborts with +msg+ + + def error(msg) + msg = make_message msg + + abort msg + end + + ## + # Looks for a true or false token. Returns false if TkFALSE or TkNIL are + # found. + + def get_bool + skip_tkspace + tk = get_tk + case tk + when TkTRUE + true + when TkFALSE, TkNIL + false + else + unget_tk tk + true + end + end + + ## + # Look for the name of a class of module (optionally with a leading :: or + # with :: separated named) and return the ultimate name, the associated + # container, and the given name (with the ::). + + def get_class_or_module container, ignore_constants = false + skip_tkspace + name_t = get_tk + given_name = '' + + # class ::A -> A is in the top level + case name_t + when TkCOLON2, TkCOLON3 then # bug + name_t = get_tk + container = @top_level + given_name << '::' + end + + skip_tkspace false + given_name << name_t.name + + while TkCOLON2 === peek_tk do + prev_container = container + container = container.find_module_named name_t.name + container ||= + if ignore_constants then + RDoc::Context.new + else + c = prev_container.add_module RDoc::NormalModule, name_t.name + c.ignore unless prev_container.document_children + @top_level.add_to_classes_or_modules c + c + end + + record_location container + + get_tk + skip_tkspace false + name_t = get_tk + given_name << '::' << name_t.name + end + + skip_tkspace false + + return [container, name_t, given_name] + end + + ## + # Return a superclass, which can be either a constant of an expression + + def get_class_specification + case peek_tk + when TkSELF then return 'self' + when TkGVAR then return '' + end + + res = get_constant + + skip_tkspace false + + get_tkread # empty out read buffer + + tk = get_tk + + case tk + when TkNL, TkCOMMENT, TkSEMICOLON then + unget_tk(tk) + return res + end + + res += parse_call_parameters(tk) + res + end + + ## + # Parse a constant, which might be qualified by one or more class or module + # names + + def get_constant + res = "" + skip_tkspace false + tk = get_tk + + while TkCOLON2 === tk or TkCOLON3 === tk or TkCONSTANT === tk do + res += tk.name + tk = get_tk + end + + unget_tk(tk) + res + end + + ## + # Get a constant that may be surrounded by parens + + def get_constant_with_optional_parens + skip_tkspace false + + nest = 0 + + while TkLPAREN === (tk = peek_tk) or TkfLPAREN === tk do + get_tk + skip_tkspace + nest += 1 + end + + name = get_constant + + while nest > 0 + skip_tkspace + tk = get_tk + nest -= 1 if TkRPAREN === tk + end + + name + end + + ## + # Little hack going on here. In the statement: + # + # f = 2*(1+yield) + # + # We see the RPAREN as the next token, so we need to exit early. This still + # won't catch all cases (such as "a = yield + 1" + + def get_end_token tk # :nodoc: + case tk + when TkLPAREN, TkfLPAREN + TkRPAREN + when TkRPAREN + nil + else + TkNL + end + end + + ## + # Retrieves the method container for a singleton method. + + def get_method_container container, name_t # :nodoc: + prev_container = container + container = container.find_module_named(name_t.name) + + unless container then + constant = prev_container.constants.find do |const| + const.name == name_t.name + end + + if constant then + parse_method_dummy prev_container + return + end + end + + unless container then + # TODO seems broken, should starting at Object in @store + obj = name_t.name.split("::").inject(Object) do |state, item| + state.const_get(item) + end rescue nil + + type = obj.class == Class ? RDoc::NormalClass : RDoc::NormalModule + + unless [Class, Module].include?(obj.class) then + warn("Couldn't find #{name_t.name}. Assuming it's a module") + end + + if type == RDoc::NormalClass then + sclass = obj.superclass ? obj.superclass.name : nil + container = prev_container.add_class type, name_t.name, sclass + else + container = prev_container.add_module type, name_t.name + end + + record_location container + end + + container + end + + ## + # Extracts a name or symbol from the token stream. + + def get_symbol_or_name + tk = get_tk + case tk + when TkSYMBOL then + text = tk.text.sub(/^:/, '') + + if TkASSIGN === peek_tk then + get_tk + text << '=' + end + + text + when TkId, TkOp then + tk.name + when TkAMPER, + TkDSTRING, + TkSTAR, + TkSTRING then + tk.text + else + raise RDoc::Error, "Name or symbol expected (got #{tk})" + end + end + + def stop_at_EXPR_END # :nodoc: + @scanner.lex_state == :EXPR_END || !@scanner.continue + end + + ## + # Marks containers between +container+ and +ancestor+ as ignored + + def suppress_parents container, ancestor # :nodoc: + while container and container != ancestor do + container.suppress unless container.documented? + container = container.parent + end + end + + ## + # Look for directives in a normal comment block: + # + # # :stopdoc: + # # Don't display comment from this point forward + # + # This routine modifies its +comment+ parameter. + + def look_for_directives_in context, comment + @preprocess.handle comment, context do |directive, param| + case directive + when 'method', 'singleton-method', + 'attr', 'attr_accessor', 'attr_reader', 'attr_writer' then + false # handled elsewhere + when 'section' then + context.set_current_section param, comment.dup + comment.text = '' + break + end + end + + remove_private_comments comment + end + + ## + # Adds useful info about the parser to +message+ + + def make_message message + prefix = "#{@file_name}:" + + prefix << "#{@scanner.line_no}:#{@scanner.char_no}:" if @scanner + + "#{prefix} #{message}" + end + + ## + # Creates a comment with the correct format + + def new_comment comment + c = RDoc::Comment.new comment, @top_level + c.format = @markup + c + end + + ## + # Creates an RDoc::Attr for the name following +tk+, setting the comment to + # +comment+. + + def parse_attr(context, single, tk, comment) + offset = tk.seek + line_no = tk.line_no + + args = parse_symbol_arg 1 + if args.size > 0 then + name = args[0] + rw = "R" + skip_tkspace false + tk = get_tk + + if TkCOMMA === tk then + rw = "RW" if get_bool + else + unget_tk tk + end + + att = create_attr context, single, name, rw, comment + att.offset = offset + att.line = line_no + + read_documentation_modifiers att, RDoc::ATTR_MODIFIERS + else + warn "'attr' ignored - looks like a variable" + end + end + + ## + # Creates an RDoc::Attr for each attribute listed after +tk+, setting the + # comment for each to +comment+. + + def parse_attr_accessor(context, single, tk, comment) + offset = tk.seek + line_no = tk.line_no + + args = parse_symbol_arg + rw = "?" + + tmp = RDoc::CodeObject.new + read_documentation_modifiers tmp, RDoc::ATTR_MODIFIERS + # TODO In most other places we let the context keep track of document_self + # and add found items appropriately but here we do not. I'm not sure why. + return if @track_visibility and not tmp.document_self + + case tk.name + when "attr_reader" then rw = "R" + when "attr_writer" then rw = "W" + when "attr_accessor" then rw = "RW" + else + rw = '?' + end + + for name in args + att = create_attr context, single, name, rw, comment + att.offset = offset + att.line = line_no + end + end + + ## + # Parses an +alias+ in +context+ with +comment+ + + def parse_alias(context, single, tk, comment) + offset = tk.seek + line_no = tk.line_no + + skip_tkspace + + if TkLPAREN === peek_tk then + get_tk + skip_tkspace + end + + new_name = get_symbol_or_name + + @scanner.lex_state = :EXPR_FNAME + + skip_tkspace + if TkCOMMA === peek_tk then + get_tk + skip_tkspace + end + + begin + old_name = get_symbol_or_name + rescue RDoc::Error + return + end + + al = RDoc::Alias.new(get_tkread, old_name, new_name, comment, + single == SINGLE) + record_location al + al.offset = offset + al.line = line_no + + read_documentation_modifiers al, RDoc::ATTR_MODIFIERS + context.add_alias al + @stats.add_alias al + + al + end + + ## + # Extracts call parameters from the token stream. + + def parse_call_parameters(tk) + end_token = case tk + when TkLPAREN, TkfLPAREN + TkRPAREN + when TkRPAREN + return "" + else + TkNL + end + nest = 0 + + loop do + case tk + when TkSEMICOLON + break + when TkLPAREN, TkfLPAREN + nest += 1 + when end_token + if end_token == TkRPAREN + nest -= 1 + break if @scanner.lex_state == :EXPR_END and nest <= 0 + else + break unless @scanner.continue + end + when TkCOMMENT, TkASSIGN, TkOPASGN + unget_tk(tk) + break + when nil then + break + end + tk = get_tk + end + + get_tkread_clean "\n", " " + end + + ## + # Parses a class in +context+ with +comment+ + + def parse_class container, single, tk, comment + offset = tk.seek + line_no = tk.line_no + + declaration_context = container + container, name_t, given_name = get_class_or_module container + + cls = + case name_t + when TkCONSTANT + parse_class_regular container, declaration_context, single, + name_t, given_name, comment + when TkLSHFT + case name = get_class_specification + when 'self', container.name + parse_statements container, SINGLE + return # don't update offset or line + else + parse_class_singleton container, name, comment + end + else + warn "Expected class name or '<<'. Got #{name_t.class}: #{name_t.text.inspect}" + return + end + + cls.offset = offset + cls.line = line_no + + cls + end + + ## + # Parses and creates a regular class + + def parse_class_regular container, declaration_context, single, # :nodoc: + name_t, given_name, comment + superclass = '::Object' + + if given_name =~ /^::/ then + declaration_context = @top_level + given_name = $' + end + + if TkLT === peek_tk then + get_tk + skip_tkspace + superclass = get_class_specification + superclass = '(unknown)' if superclass.empty? + end + + cls_type = single == SINGLE ? RDoc::SingleClass : RDoc::NormalClass + cls = declaration_context.add_class cls_type, given_name, superclass + cls.ignore unless container.document_children + + read_documentation_modifiers cls, RDoc::CLASS_MODIFIERS + record_location cls + + cls.add_comment comment, @top_level + + @top_level.add_to_classes_or_modules cls + @stats.add_class cls + + suppress_parents container, declaration_context unless cls.document_self + + parse_statements cls + + cls + end + + ## + # Parses a singleton class in +container+ with the given +name+ and + # +comment+. + + def parse_class_singleton container, name, comment # :nodoc: + other = @store.find_class_named name + + unless other then + if name =~ /^::/ then + name = $' + container = @top_level + end + + other = container.add_module RDoc::NormalModule, name + record_location other + + # class << $gvar + other.ignore if name.empty? + + other.add_comment comment, @top_level + end + + # notify :nodoc: all if not a constant-named class/module + # (and remove any comment) + unless name =~ /\A(::)?[A-Z]/ then + other.document_self = nil + other.document_children = false + other.clear_comment + end + + @top_level.add_to_classes_or_modules other + @stats.add_class other + + read_documentation_modifiers other, RDoc::CLASS_MODIFIERS + parse_statements(other, SINGLE) + + other + end + + ## + # Parses a constant in +context+ with +comment+. If +ignore_constants+ is + # true, no found constants will be added to RDoc. + + def parse_constant container, tk, comment, ignore_constants = false + offset = tk.seek + line_no = tk.line_no + + name = tk.name + skip_tkspace false + + return unless name =~ /^\w+$/ + + eq_tk = get_tk + + if TkCOLON2 === eq_tk then + unget_tk eq_tk + unget_tk tk + + container, name_t, = get_class_or_module container, ignore_constants + + name = name_t.name + + eq_tk = get_tk + end + + unless TkASSIGN === eq_tk then + unget_tk eq_tk + return false + end + + if TkGT === peek_tk then + unget_tk eq_tk + return + end + + value = '' + con = RDoc::Constant.new name, value, comment + + body = parse_constant_body container, con + + return unless body + + value.replace body + record_location con + con.offset = offset + con.line = line_no + read_documentation_modifiers con, RDoc::CONSTANT_MODIFIERS + + @stats.add_constant con + container.add_constant con + + true + end + + def parse_constant_body container, constant # :nodoc: + nest = 0 + rhs_name = '' + + get_tkread + + tk = get_tk + + loop do + case tk + when TkSEMICOLON then + break if nest <= 0 + when TkLPAREN, TkfLPAREN, TkLBRACE, TkfLBRACE, TkLBRACK, TkfLBRACK, + TkDO, TkIF, TkUNLESS, TkCASE, TkDEF, TkBEGIN then + nest += 1 + when TkRPAREN, TkRBRACE, TkRBRACK, TkEND then + nest -= 1 + when TkCOMMENT then + if nest <= 0 and stop_at_EXPR_END then + unget_tk tk + break + else + unget_tk tk + read_documentation_modifiers constant, RDoc::CONSTANT_MODIFIERS + end + when TkCONSTANT then + rhs_name << tk.name + + if nest <= 0 and TkNL === peek_tk then + create_module_alias container, constant, rhs_name + break + end + when TkNL then + if nest <= 0 and stop_at_EXPR_END then + unget_tk tk + break + end + when TkCOLON2, TkCOLON3 then + rhs_name << '::' + when nil then + break + end + tk = get_tk + end + + get_tkread_clean(/^[ \t]+/, '') + end + + ## + # Generates an RDoc::Method or RDoc::Attr from +comment+ by looking for + # :method: or :attr: directives in +comment+. + + def parse_comment container, tk, comment + return parse_comment_tomdoc container, tk, comment if @markup == 'tomdoc' + column = tk.char_no + offset = tk.seek + line_no = tk.line_no + + text = comment.text + + singleton = !!text.sub!(/(^# +:?)(singleton-)(method:)/, '\1\3') + + co = + if text.sub!(/^# +:?method: *(\S*).*?\n/i, '') then + parse_comment_ghost container, text, $1, column, line_no, comment + elsif text.sub!(/# +:?(attr(_reader|_writer|_accessor)?): *(\S*).*?\n/i, '') then + parse_comment_attr container, $1, $3, comment + end + + if co then + co.singleton = singleton + co.offset = offset + co.line = line_no + end + + true + end + + ## + # Parse a comment that is describing an attribute in +container+ with the + # given +name+ and +comment+. + + def parse_comment_attr container, type, name, comment # :nodoc: + return if name.empty? + + rw = case type + when 'attr_reader' then 'R' + when 'attr_writer' then 'W' + else 'RW' + end + + create_attr container, NORMAL, name, rw, comment + end + + def parse_comment_ghost container, text, name, column, line_no, # :nodoc: + comment + name = nil if name.empty? + + meth = RDoc::GhostMethod.new get_tkread, name + record_location meth + + meth.start_collecting_tokens + indent = TkSPACE.new 0, 1, 1 + indent.set_text " " * column + + position_comment = TkCOMMENT.new 0, line_no, 1 + position_comment.set_text "# File #{@top_level.relative_name}, line #{line_no}" + meth.add_tokens [position_comment, NEWLINE_TOKEN, indent] + + meth.params = + if text.sub!(/^#\s+:?args?:\s*(.*?)\s*$/i, '') then + $1 + else + '' + end + + comment.normalize + comment.extract_call_seq meth + + return unless meth.name + + container.add_method meth + + meth.comment = comment + + @stats.add_method meth + + meth + end + + ## + # Creates an RDoc::Method on +container+ from +comment+ if there is a + # Signature section in the comment + + def parse_comment_tomdoc container, tk, comment + return unless signature = RDoc::TomDoc.signature(comment) + offset = tk.seek + line_no = tk.line_no + + name, = signature.split %r%[ \(]%, 2 + + meth = RDoc::GhostMethod.new get_tkread, name + record_location meth + meth.offset = offset + meth.line = line_no + + meth.start_collecting_tokens + indent = TkSPACE.new 0, 1, 1 + indent.set_text " " * offset + + position_comment = TkCOMMENT.new 0, line_no, 1 + position_comment.set_text "# File #{@top_level.relative_name}, line #{line_no}" + meth.add_tokens [position_comment, NEWLINE_TOKEN, indent] + + meth.call_seq = signature + + comment.normalize + + return unless meth.name + + container.add_method meth + + meth.comment = comment + + @stats.add_method meth + end + + ## + # Parses an +include+ or +extend+, indicated by the +klass+ and adds it to + # +container+ # with +comment+ + + def parse_extend_or_include klass, container, comment # :nodoc: + loop do + skip_tkspace_comment + + name = get_constant_with_optional_parens + + unless name.empty? then + obj = container.add klass, name, comment + record_location obj + end + + return unless TkCOMMA === peek_tk + + get_tk + end + end + + ## + # Parses identifiers that can create new methods or change visibility. + # + # Returns true if the comment was not consumed. + + def parse_identifier container, single, tk, comment # :nodoc: + case tk.name + when 'private', 'protected', 'public', 'private_class_method', + 'public_class_method', 'module_function' then + parse_visibility container, single, tk + return true + when 'attr' then + parse_attr container, single, tk, comment + when /^attr_(reader|writer|accessor)$/ then + parse_attr_accessor container, single, tk, comment + when 'alias_method' then + parse_alias container, single, tk, comment + when 'require', 'include' then + # ignore + else + if comment.text =~ /\A#\#$/ then + case comment.text + when /^# +:?attr(_reader|_writer|_accessor)?:/ then + parse_meta_attr container, single, tk, comment + else + method = parse_meta_method container, single, tk, comment + method.params = container.params if + container.params + method.block_params = container.block_params if + container.block_params + end + end + end + + false + end + + ## + # Parses a meta-programmed attribute and creates an RDoc::Attr. + # + # To create foo and bar attributes on class C with comment "My attributes": + # + # class C + # + # ## + # # :attr: + # # + # # My attributes + # + # my_attr :foo, :bar + # + # end + # + # To create a foo attribute on class C with comment "My attribute": + # + # class C + # + # ## + # # :attr: foo + # # + # # My attribute + # + # my_attr :foo, :bar + # + # end + + def parse_meta_attr(context, single, tk, comment) + args = parse_symbol_arg + rw = "?" + + # If nodoc is given, don't document any of them + + tmp = RDoc::CodeObject.new + read_documentation_modifiers tmp, RDoc::ATTR_MODIFIERS + + if comment.text.sub!(/^# +:?(attr(_reader|_writer|_accessor)?): *(\S*).*?\n/i, '') then + rw = case $1 + when 'attr_reader' then 'R' + when 'attr_writer' then 'W' + else 'RW' + end + name = $3 unless $3.empty? + end + + if name then + att = create_attr context, single, name, rw, comment + else + args.each do |attr_name| + att = create_attr context, single, attr_name, rw, comment + end + end + + att + end + + ## + # Parses a meta-programmed method + + def parse_meta_method(container, single, tk, comment) + column = tk.char_no + offset = tk.seek + line_no = tk.line_no + + start_collecting_tokens + add_token tk + add_token_listener self + + skip_tkspace false + + singleton = !!comment.text.sub!(/(^# +:?)(singleton-)(method:)/, '\1\3') + + name = parse_meta_method_name comment, tk + + return unless name + + meth = RDoc::MetaMethod.new get_tkread, name + record_location meth + meth.offset = offset + meth.line = line_no + meth.singleton = singleton + + remove_token_listener self + + meth.start_collecting_tokens + indent = TkSPACE.new 0, 1, 1 + indent.set_text " " * column + + position_comment = TkCOMMENT.new 0, line_no, 1 + position_comment.value = "# File #{@top_level.relative_name}, line #{line_no}" + meth.add_tokens [position_comment, NEWLINE_TOKEN, indent] + meth.add_tokens @token_stream + + parse_meta_method_params container, single, meth, tk, comment + + meth.comment = comment + + @stats.add_method meth + + meth + end + + ## + # Parses the name of a metaprogrammed method. +comment+ is used to + # determine the name while +tk+ is used in an error message if the name + # cannot be determined. + + def parse_meta_method_name comment, tk # :nodoc: + if comment.text.sub!(/^# +:?method: *(\S*).*?\n/i, '') then + return $1 unless $1.empty? + end + + name_t = get_tk + + case name_t + when TkSYMBOL then + name_t.text[1..-1] + when TkSTRING then + name_t.value[1..-2] + when TkASSIGN then # ignore + remove_token_listener self + + nil + else + warn "unknown name token #{name_t.inspect} for meta-method '#{tk.name}'" + 'unknown' + end + end + + ## + # Parses the parameters and block for a meta-programmed method. + + def parse_meta_method_params container, single, meth, tk, comment # :nodoc: + token_listener meth do + meth.params = '' + + comment.normalize + comment.extract_call_seq meth + + container.add_method meth + + last_tk = tk + + while tk = get_tk do + case tk + when TkSEMICOLON then + break + when TkNL then + break unless last_tk and TkCOMMA === last_tk + when TkSPACE then + # expression continues + when TkDO then + parse_statements container, single, meth + break + else + last_tk = tk + end + end + end + end + + ## + # Parses a normal method defined by +def+ + + def parse_method(container, single, tk, comment) + singleton = nil + added_container = false + name = nil + column = tk.char_no + offset = tk.seek + line_no = tk.line_no + + start_collecting_tokens + add_token tk + + token_listener self do + prev_container = container + name, container, singleton = parse_method_name container + added_container = container != prev_container + end + + return unless name + + meth = RDoc::AnyMethod.new get_tkread, name + meth.singleton = single == SINGLE ? true : singleton + + record_location meth + meth.offset = offset + meth.line = line_no + + meth.start_collecting_tokens + indent = TkSPACE.new 0, 1, 1 + indent.set_text " " * column + + token = TkCOMMENT.new 0, line_no, 1 + token.set_text "# File #{@top_level.relative_name}, line #{line_no}" + meth.add_tokens [token, NEWLINE_TOKEN, indent] + meth.add_tokens @token_stream + + parse_method_params_and_body container, single, meth, added_container + + comment.normalize + comment.extract_call_seq meth + + meth.comment = comment + + @stats.add_method meth + end + + ## + # Parses the parameters and body of +meth+ + + def parse_method_params_and_body container, single, meth, added_container + token_listener meth do + @scanner.continue = false + parse_method_parameters meth + + if meth.document_self or not @track_visibility then + container.add_method meth + elsif added_container then + container.document_self = false + end + + # Having now read the method parameters and documentation modifiers, we + # now know whether we have to rename #initialize to ::new + + if meth.name == "initialize" && !meth.singleton then + if meth.dont_rename_initialize then + meth.visibility = :protected + else + meth.singleton = true + meth.name = "new" + meth.visibility = :public + end + end + + parse_statements container, single, meth + end + end + + ## + # Parses a method that needs to be ignored. + + def parse_method_dummy container + dummy = RDoc::Context.new + dummy.parent = container + dummy.store = container.store + skip_method dummy + end + + ## + # Parses the name of a method in +container+. + # + # Returns the method name, the container it is in (for def Foo.name) and if + # it is a singleton or regular method. + + def parse_method_name container # :nodoc: + @scanner.lex_state = :EXPR_FNAME + + skip_tkspace + name_t = get_tk + back_tk = skip_tkspace + singleton = false + + case dot = get_tk + when TkDOT, TkCOLON2 then + singleton = true + + name, container = parse_method_name_singleton container, name_t + else + unget_tk dot + back_tk.reverse_each do |token| + unget_tk token + end + + name = parse_method_name_regular container, name_t + end + + return name, container, singleton + end + + ## + # For the given +container+ and initial name token +name_t+ the method name + # is parsed from the token stream for a regular method. + + def parse_method_name_regular container, name_t # :nodoc: + case name_t + when TkSTAR, TkAMPER then + name_t.text + else + unless name_t.respond_to? :name then + warn "expected method name token, . or ::, got #{name_t.inspect}" + skip_method container + return + end + name_t.name + end + end + + ## + # For the given +container+ and initial name token +name_t+ the method name + # and the new +container+ (if necessary) are parsed from the token stream + # for a singleton method. + + def parse_method_name_singleton container, name_t # :nodoc: + @scanner.lex_state = :EXPR_FNAME + skip_tkspace + name_t2 = get_tk + + name = + case name_t + when TkSELF, TkMOD then + case name_t2 + # NOTE: work around '[' being consumed early and not being re-tokenized + # as a TkAREF + when TkfLBRACK then + get_tk + '[]' + else + name_t2.name + end + when TkCONSTANT then + name = name_t2.name + + container = get_method_container container, name_t + + return unless container + + name + when TkIDENTIFIER, TkIVAR, TkGVAR then + parse_method_dummy container + + nil + when TkTRUE, TkFALSE, TkNIL then + klass_name = "#{name_t.name.capitalize}Class" + container = @store.find_class_named klass_name + container ||= @top_level.add_class RDoc::NormalClass, klass_name + + name_t2.name + else + warn "unexpected method name token #{name_t.inspect}" + # break + skip_method container + + nil + end + + return name, container + end + + ## + # Extracts +yield+ parameters from +method+ + + def parse_method_or_yield_parameters(method = nil, + modifiers = RDoc::METHOD_MODIFIERS) + skip_tkspace false + tk = get_tk + end_token = get_end_token tk + return '' unless end_token + + nest = 0 + + loop do + case tk + when TkSEMICOLON then + break if nest == 0 + when TkLBRACE, TkfLBRACE then + nest += 1 + when TkRBRACE then + nest -= 1 + if nest <= 0 + # we might have a.each { |i| yield i } + unget_tk(tk) if nest < 0 + break + end + when TkLPAREN, TkfLPAREN then + nest += 1 + when end_token then + if end_token == TkRPAREN + nest -= 1 + break if nest <= 0 + else + break unless @scanner.continue + end + when TkRPAREN then + nest -= 1 + when method && method.block_params.nil? && TkCOMMENT then + unget_tk tk + read_documentation_modifiers method, modifiers + @read.pop + when TkCOMMENT then + @read.pop + when nil then + break + end + tk = get_tk + end + + get_tkread_clean(/\s+/, ' ') + end + + ## + # Capture the method's parameters. Along the way, look for a comment + # containing: + # + # # yields: .... + # + # and add this as the block_params for the method + + def parse_method_parameters method + res = parse_method_or_yield_parameters method + + res = "(#{res})" unless res =~ /\A\(/ + method.params = res unless method.params + + return if method.block_params + + skip_tkspace false + read_documentation_modifiers method, RDoc::METHOD_MODIFIERS + end + + ## + # Parses an RDoc::NormalModule in +container+ with +comment+ + + def parse_module container, single, tk, comment + container, name_t, = get_class_or_module container + + name = name_t.name + + mod = container.add_module RDoc::NormalModule, name + mod.ignore unless container.document_children + record_location mod + + read_documentation_modifiers mod, RDoc::CLASS_MODIFIERS + mod.add_comment comment, @top_level + parse_statements mod + + @stats.add_module mod + end + + ## + # Parses an RDoc::Require in +context+ containing +comment+ + + def parse_require(context, comment) + skip_tkspace_comment + tk = get_tk + + if TkLPAREN === tk then + skip_tkspace_comment + tk = get_tk + end + + name = tk.text if TkSTRING === tk + + if name then + @top_level.add_require RDoc::Require.new(name, comment) + else + unget_tk tk + end + end + + ## + # Parses a rescue + + def parse_rescue + skip_tkspace false + + while tk = get_tk + case tk + when TkNL, TkSEMICOLON then + break + when TkCOMMA then + skip_tkspace false + + get_tk if TkNL === peek_tk + end + + skip_tkspace false + end + end + + ## + # The core of the Ruby parser. + + def parse_statements(container, single = NORMAL, current_method = nil, + comment = new_comment('')) + raise 'no' unless RDoc::Comment === comment + comment.force_encoding @encoding if @encoding + + nest = 1 + save_visibility = container.visibility + + non_comment_seen = true + + while tk = get_tk do + keep_comment = false + try_parse_comment = false + + non_comment_seen = true unless TkCOMMENT === tk + + case tk + when TkNL then + skip_tkspace + tk = get_tk + + if TkCOMMENT === tk then + if non_comment_seen then + # Look for RDoc in a comment about to be thrown away + non_comment_seen = parse_comment container, tk, comment unless + comment.empty? + + comment = '' + comment.force_encoding @encoding if @encoding + end + + while TkCOMMENT === tk do + comment << tk.text << "\n" + + tk = get_tk + + if TkNL === tk then + skip_tkspace false # leading spaces + tk = get_tk + end + end + + comment = new_comment comment + + unless comment.empty? then + look_for_directives_in container, comment + + if container.done_documenting then + throw :eof if RDoc::TopLevel === container + container.ongoing_visibility = save_visibility + end + end + + keep_comment = true + else + non_comment_seen = true + end + + unget_tk tk + keep_comment = true + + when TkCLASS then + parse_class container, single, tk, comment + + when TkMODULE then + parse_module container, single, tk, comment + + when TkDEF then + parse_method container, single, tk, comment + + when TkCONSTANT then + unless parse_constant container, tk, comment, current_method then + try_parse_comment = true + end + + when TkALIAS then + parse_alias container, single, tk, comment unless current_method + + when TkYIELD then + if current_method.nil? then + warn "Warning: yield outside of method" if container.document_self + else + parse_yield container, single, tk, current_method + end + + # Until and While can have a 'do', which shouldn't increase the nesting. + # We can't solve the general case, but we can handle most occurrences by + # ignoring a do at the end of a line. + + when TkUNTIL, TkWHILE then + nest += 1 + skip_optional_do_after_expression + + # 'for' is trickier + when TkFOR then + nest += 1 + skip_for_variable + skip_optional_do_after_expression + + when TkCASE, TkDO, TkIF, TkUNLESS, TkBEGIN then + nest += 1 + + when TkSUPER then + current_method.calls_super = true if current_method + + when TkRESCUE then + parse_rescue + + when TkIDENTIFIER then + if nest == 1 and current_method.nil? then + keep_comment = parse_identifier container, single, tk, comment + end + + case tk.name + when "require" then + parse_require container, comment + when "include" then + parse_extend_or_include RDoc::Include, container, comment + when "extend" then + parse_extend_or_include RDoc::Extend, container, comment + end + + when TkEND then + nest -= 1 + if nest == 0 then + read_documentation_modifiers container, RDoc::CLASS_MODIFIERS + container.ongoing_visibility = save_visibility + + parse_comment container, tk, comment unless comment.empty? + + return + end + else + try_parse_comment = nest == 1 + end + + if try_parse_comment then + non_comment_seen = parse_comment container, tk, comment unless + comment.empty? + + keep_comment = false + end + + unless keep_comment then + comment = new_comment '' + comment.force_encoding @encoding if @encoding + container.params = nil + container.block_params = nil + end + + consume_trailing_spaces + end + + container.params = nil + container.block_params = nil + end + + ## + # Parse up to +no+ symbol arguments + + def parse_symbol_arg(no = nil) + skip_tkspace_comment + + case tk = get_tk + when TkLPAREN + parse_symbol_arg_paren no + else + parse_symbol_arg_space no, tk + end + end + + ## + # Parses up to +no+ symbol arguments surrounded by () and places them in + # +args+. + + def parse_symbol_arg_paren no # :nodoc: + args = [] + + loop do + skip_tkspace_comment + if tk1 = parse_symbol_in_arg + args.push tk1 + break if no and args.size >= no + end + + skip_tkspace_comment + case tk2 = get_tk + when TkRPAREN + break + when TkCOMMA + else + warn("unexpected token: '#{tk2.inspect}'") if $DEBUG_RDOC + break + end + end + + args + end + + ## + # Parses up to +no+ symbol arguments separated by spaces and places them in + # +args+. + + def parse_symbol_arg_space no, tk # :nodoc: + args = [] + + unget_tk tk + if tk = parse_symbol_in_arg + args.push tk + return args if no and args.size >= no + end + + loop do + skip_tkspace false + + tk1 = get_tk + unless TkCOMMA === tk1 then + unget_tk tk1 + break + end + + skip_tkspace_comment + if tk = parse_symbol_in_arg + args.push tk + break if no and args.size >= no + end + end + + args + end + + ## + # Returns symbol text from the next token + + def parse_symbol_in_arg + case tk = get_tk + when TkSYMBOL + tk.text.sub(/^:/, '') + when TkSTRING + eval @read[-1] + when TkDSTRING, TkIDENTIFIER then + nil # ignore + else + warn("Expected symbol or string, got #{tk.inspect}") if $DEBUG_RDOC + nil + end + end + + ## + # Parses statements in the top-level +container+ + + def parse_top_level_statements container + comment = collect_first_comment + + look_for_directives_in container, comment + + throw :eof if container.done_documenting + + @markup = comment.format + + # HACK move if to RDoc::Context#comment= + container.comment = comment if container.document_self unless comment.empty? + + parse_statements container, NORMAL, nil, comment + end + + ## + # Determines the visibility in +container+ from +tk+ + + def parse_visibility(container, single, tk) + vis_type, vis, singleton = get_visibility_information tk, single + + skip_tkspace_comment false + + case peek_tk + # Ryan Davis suggested the extension to ignore modifiers, because he + # often writes + # + # protected unless $TESTING + # + when TkNL, TkUNLESS_MOD, TkIF_MOD, TkSEMICOLON then + container.ongoing_visibility = vis + else + update_visibility container, vis_type, vis, singleton + end + end + + ## + # Determines the block parameter for +context+ + + def parse_yield(context, single, tk, method) + return if method.block_params + + get_tkread + @scanner.continue = false + method.block_params = parse_method_or_yield_parameters + end + + ## + # Directives are modifier comments that can appear after class, module, or + # method names. For example: + # + # def fred # :yields: a, b + # + # or: + # + # class MyClass # :nodoc: + # + # We return the directive name and any parameters as a two element array if + # the name is in +allowed+. A directive can be found anywhere up to the end + # of the current line. + + def read_directive allowed + tokens = [] + + while tk = get_tk do + tokens << tk + + case tk + when TkNL, TkDEF then + return + when TkCOMMENT then + return unless tk.text =~ /\s*:?([\w-]+):\s*(.*)/ + + directive = $1.downcase + + return [directive, $2] if allowed.include? directive + + return + end + end + ensure + unless tokens.length == 1 and TkCOMMENT === tokens.first then + tokens.reverse_each do |token| + unget_tk token + end + end + end + + ## + # Handles directives following the definition for +context+ (any + # RDoc::CodeObject) if the directives are +allowed+ at this point. + # + # See also RDoc::Markup::PreProcess#handle_directive + + def read_documentation_modifiers context, allowed + directive, value = read_directive allowed + + return unless directive + + @preprocess.handle_directive '', directive, value, context do |dir, param| + if %w[notnew not_new not-new].include? dir then + context.dont_rename_initialize = true + + true + end + end + end + + ## + # Records the location of this +container+ in the file for this parser and + # adds it to the list of classes and modules in the file. + + def record_location container # :nodoc: + case container + when RDoc::ClassModule then + @top_level.add_to_classes_or_modules container + end + + container.record_location @top_level + end + + ## + # Removes private comments from +comment+ + #-- + # TODO remove + + def remove_private_comments comment + comment.remove_private + end + + ## + # Scans this Ruby file for Ruby constructs + + def scan + reset + + catch :eof do + begin + parse_top_level_statements @top_level + + rescue StandardError => e + bytes = '' + + 20.times do @scanner.ungetc end + count = 0 + 60.times do |i| + count = i + byte = @scanner.getc + break unless byte + bytes << byte + end + count -= 20 + count.times do @scanner.ungetc end + + $stderr.puts <<-EOF + +#{self.class} failure around line #{@scanner.line_no} of +#{@file_name} + + EOF + + unless bytes.empty? then + $stderr.puts + $stderr.puts bytes.inspect + end + + raise e + end + end + + @top_level + end + + ## + # while, until, and for have an optional do + + def skip_optional_do_after_expression + skip_tkspace false + tk = get_tk + end_token = get_end_token tk + + b_nest = 0 + nest = 0 + @scanner.continue = false + + loop do + case tk + when TkSEMICOLON then + break if b_nest.zero? + when TkLPAREN, TkfLPAREN then + nest += 1 + when TkBEGIN then + b_nest += 1 + when TkEND then + b_nest -= 1 + when TkDO + break if nest.zero? + when end_token then + if end_token == TkRPAREN + nest -= 1 + break if @scanner.lex_state == :EXPR_END and nest.zero? + else + break unless @scanner.continue + end + when nil then + break + end + tk = get_tk + end + + skip_tkspace false + + get_tk if TkDO === peek_tk + end + + ## + # skip the var [in] part of a 'for' statement + + def skip_for_variable + skip_tkspace false + get_tk + skip_tkspace false + tk = get_tk + unget_tk(tk) unless TkIN === tk + end + + ## + # Skips the next method in +container+ + + def skip_method container + meth = RDoc::AnyMethod.new "", "anon" + parse_method_parameters meth + parse_statements container, false, meth + end + + ## + # Skip spaces until a comment is found + + def skip_tkspace_comment(skip_nl = true) + loop do + skip_tkspace skip_nl + return unless TkCOMMENT === peek_tk + get_tk + end + end + + ## + # Updates visibility in +container+ from +vis_type+ and +vis+. + + def update_visibility container, vis_type, vis, singleton # :nodoc: + new_methods = [] + + case vis_type + when 'module_function' then + args = parse_symbol_arg + container.set_visibility_for args, :private, false + + container.methods_matching args do |m| + s_m = m.dup + record_location s_m + s_m.singleton = true + new_methods << s_m + end + when 'public_class_method', 'private_class_method' then + args = parse_symbol_arg + + container.methods_matching args, true do |m| + if m.parent != container then + m = m.dup + record_location m + new_methods << m + end + + m.visibility = vis + end + else + args = parse_symbol_arg + container.set_visibility_for args, vis, singleton + end + + new_methods.each do |method| + case method + when RDoc::AnyMethod then + container.add_method method + when RDoc::Attr then + container.add_attribute method + end + method.visibility = vis + end + end + + ## + # Prints +message+ to +$stderr+ unless we're being quiet + + def warn message + @options.warn make_message message + end + +end + diff --git a/jni/ruby/lib/rdoc/parser/ruby_tools.rb b/jni/ruby/lib/rdoc/parser/ruby_tools.rb new file mode 100644 index 0000000..654431e --- /dev/null +++ b/jni/ruby/lib/rdoc/parser/ruby_tools.rb @@ -0,0 +1,167 @@ +## +# Collection of methods for writing parsers against RDoc::RubyLex and +# RDoc::RubyToken + +module RDoc::Parser::RubyTools + + include RDoc::RubyToken + + ## + # Adds a token listener +obj+, but you should probably use token_listener + + def add_token_listener(obj) + @token_listeners ||= [] + @token_listeners << obj + end + + ## + # Fetches the next token from the scanner + + def get_tk + tk = nil + + if @tokens.empty? then + tk = @scanner.token + @read.push @scanner.get_readed + puts "get_tk1 => #{tk.inspect}" if $TOKEN_DEBUG + else + @read.push @unget_read.shift + tk = @tokens.shift + puts "get_tk2 => #{tk.inspect}" if $TOKEN_DEBUG + end + + tk = nil if TkEND_OF_SCRIPT === tk + + if TkSYMBEG === tk then + set_token_position tk.line_no, tk.char_no + + case tk1 = get_tk + when TkId, TkOp, TkSTRING, TkDSTRING, TkSTAR, TkAMPER then + if tk1.respond_to?(:name) then + tk = Token(TkSYMBOL).set_text(":" + tk1.name) + else + tk = Token(TkSYMBOL).set_text(":" + tk1.text) + end + + # remove the identifier we just read to replace it with a symbol + @token_listeners.each do |obj| + obj.pop_token + end if @token_listeners + else + tk = tk1 + end + end + + # inform any listeners of our shiny new token + @token_listeners.each do |obj| + obj.add_token(tk) + end if @token_listeners + + tk + end + + ## + # Reads and returns all tokens up to one of +tokens+. Leaves the matched + # token in the token list. + + def get_tk_until(*tokens) + read = [] + + loop do + tk = get_tk + + case tk + when *tokens then + unget_tk tk + break + end + + read << tk + end + + read + end + + ## + # Retrieves a String representation of the read tokens + + def get_tkread + read = @read.join("") + @read = [] + read + end + + ## + # Peek equivalent for get_tkread + + def peek_read + @read.join('') + end + + ## + # Peek at the next token, but don't remove it from the stream + + def peek_tk + unget_tk(tk = get_tk) + tk + end + + ## + # Removes the token listener +obj+ + + def remove_token_listener(obj) + @token_listeners.delete(obj) + end + + ## + # Resets the tools + + def reset + @read = [] + @tokens = [] + @unget_read = [] + @nest = 0 + end + + ## + # Skips whitespace tokens including newlines if +skip_nl+ is true + + def skip_tkspace(skip_nl = true) # HACK dup + tokens = [] + + while TkSPACE === (tk = get_tk) or (skip_nl and TkNL === tk) do + tokens.push tk + end + + unget_tk tk + tokens + end + + ## + # Has +obj+ listen to tokens + + def token_listener(obj) + add_token_listener obj + yield + ensure + remove_token_listener obj + end + + ## + # Returns +tk+ to the scanner + + def unget_tk(tk) + @tokens.unshift tk + @unget_read.unshift @read.pop + + # Remove this token from any listeners + @token_listeners.each do |obj| + obj.pop_token + end if @token_listeners + + nil + end + +end + + diff --git a/jni/ruby/lib/rdoc/parser/simple.rb b/jni/ruby/lib/rdoc/parser/simple.rb new file mode 100644 index 0000000..65cfc1b --- /dev/null +++ b/jni/ruby/lib/rdoc/parser/simple.rb @@ -0,0 +1,61 @@ +## +# Parse a non-source file. We basically take the whole thing as one big +# comment. + +class RDoc::Parser::Simple < RDoc::Parser + + include RDoc::Parser::Text + + parse_files_matching(//) + + attr_reader :content # :nodoc: + + ## + # Prepare to parse a plain file + + def initialize(top_level, file_name, content, options, stats) + super + + preprocess = RDoc::Markup::PreProcess.new @file_name, @options.rdoc_include + + preprocess.handle @content, @top_level + end + + ## + # Extract the file contents and attach them to the TopLevel as a comment + + def scan + comment = remove_coding_comment @content + comment = remove_private_comment comment + + comment = RDoc::Comment.new comment, @top_level + + @top_level.comment = comment + @top_level + end + + ## + # Removes the encoding magic comment from +text+ + + def remove_coding_comment text + text.sub(/\A# .*coding[=:].*$/, '') + end + + ## + # Removes private comments. + # + # Unlike RDoc::Comment#remove_private this implementation only looks for two + # dashes at the beginning of the line. Three or more dashes are considered + # to be a rule and ignored. + + def remove_private_comment comment + # Workaround for gsub encoding for Ruby 1.9.2 and earlier + empty = '' + empty.force_encoding comment.encoding if Object.const_defined? :Encoding + + comment = comment.gsub(%r%^--\n.*?^\+\+\n?%m, empty) + comment.sub(%r%^--\n.*%m, empty) + end + +end + diff --git a/jni/ruby/lib/rdoc/parser/text.rb b/jni/ruby/lib/rdoc/parser/text.rb new file mode 100644 index 0000000..f973313 --- /dev/null +++ b/jni/ruby/lib/rdoc/parser/text.rb @@ -0,0 +1,11 @@ +## +# Indicates this parser is text and doesn't contain code constructs. +# +# Include this module in a RDoc::Parser subclass to make it show up as a file, +# not as part of a class or module. +#-- +# This is not named File to avoid overriding ::File + +module RDoc::Parser::Text +end + diff --git a/jni/ruby/lib/rdoc/rd.rb b/jni/ruby/lib/rdoc/rd.rb new file mode 100644 index 0000000..28c5d28 --- /dev/null +++ b/jni/ruby/lib/rdoc/rd.rb @@ -0,0 +1,99 @@ +## +# RDoc::RD implements the RD format from the rdtool gem. +# +# To choose RD as your only default format see +# RDoc::Options@Saved+Options for instructions on setting up a +# <code>.doc_options</code> file to store your project default. +# +# == LICENSE +# +# The grammar that produces RDoc::RD::BlockParser and RDoc::RD::InlineParser +# is included in RDoc under the Ruby License. +# +# You can find the original source for rdtool at +# https://github.com/uwabami/rdtool/ +# +# You can use, re-distribute or change these files under Ruby's License or GPL. +# +# 1. You may make and give away verbatim copies of the source form of the +# software without restriction, provided that you duplicate all of the +# original copyright notices and associated disclaimers. +# +# 2. You may modify your copy of the software in any way, provided that +# you do at least ONE of the following: +# +# a. place your modifications in the Public Domain or otherwise +# make them Freely Available, such as by posting said +# modifications to Usenet or an equivalent medium, or by allowing +# the author to include your modifications in the software. +# +# b. use the modified software only within your corporation or +# organization. +# +# c. give non-standard binaries non-standard names, with +# instructions on where to get the original software distribution. +# +# d. make other distribution arrangements with the author. +# +# 3. You may distribute the software in object code or binary form, +# provided that you do at least ONE of the following: +# +# a. distribute the binaries and library files of the software, +# together with instructions (in the manual page or equivalent) +# on where to get the original distribution. +# +# b. accompany the distribution with the machine-readable source of +# the software. +# +# c. give non-standard binaries non-standard names, with +# instructions on where to get the original software distribution. +# +# d. make other distribution arrangements with the author. +# +# 4. You may modify and include the part of the software into any other +# software (possibly commercial). But some files in the distribution +# are not written by the author, so that they are not under these terms. +# +# For the list of those files and their copying conditions, see the +# file LEGAL. +# +# 5. The scripts and library files supplied as input to or produced as +# output from the software do not automatically fall under the +# copyright of the software, but belong to whomever generated them, +# and may be sold commercially, and may be aggregated with this +# software. +# +# 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE. + +class RDoc::RD + + ## + # Parses +rd+ source and returns an RDoc::Markup::Document. If the + # <tt>=begin</tt> or <tt>=end</tt> lines are missing they will be added. + + def self.parse rd + rd = rd.lines.to_a + + if rd.find { |i| /\S/ === i } and !rd.find{|i| /^=begin\b/ === i } then + rd.unshift("=begin\n").push("=end\n") + end + + parser = RDoc::RD::BlockParser.new + document = parser.parse rd + + # isn't this always true? + document.parts.shift if RDoc::Markup::BlankLine === document.parts.first + document.parts.pop if RDoc::Markup::BlankLine === document.parts.last + + document + end + + autoload :BlockParser, 'rdoc/rd/block_parser' + autoload :InlineParser, 'rdoc/rd/inline_parser' + autoload :Inline, 'rdoc/rd/inline' + +end + diff --git a/jni/ruby/lib/rdoc/rd/block_parser.rb b/jni/ruby/lib/rdoc/rd/block_parser.rb new file mode 100644 index 0000000..ac754f4 --- /dev/null +++ b/jni/ruby/lib/rdoc/rd/block_parser.rb @@ -0,0 +1,1055 @@ +# +# DO NOT MODIFY!!!! +# This file is automatically generated by Racc 1.4.12 +# from Racc grammer file "". +# + +require 'racc/parser.rb' + +class RDoc::RD + +## +# RD format parser for headings, paragraphs, lists, verbatim sections that +# exist as blocks. + +class BlockParser < Racc::Parser + + +# :stopdoc: + +TMPFILE = ["rdtmp", $$, 0] + +MARK_TO_LEVEL = { + '=' => 1, + '==' => 2, + '===' => 3, + '====' => 4, + '+' => 5, + '++' => 6, +} + +# :startdoc: + +## +# Footnotes for this document + +attr_reader :footnotes + +## +# Labels for items in this document + +attr_reader :labels + +## +# Path to find included files in + +attr_accessor :include_path + +## +# Creates a new RDoc::RD::BlockParser. Use #parse to parse an rd-format +# document. + +def initialize + @inline_parser = RDoc::RD::InlineParser.new self + @include_path = [] + + # for testing + @footnotes = [] + @labels = {} +end + +## +# Parses +src+ and returns an RDoc::Markup::Document. + +def parse src + @src = src + @src.push false + + @footnotes = [] + @labels = {} + + # @i: index(line no.) of src + @i = 0 + + # stack for current indentation + @indent_stack = [] + + # how indented. + @current_indent = @indent_stack.join("") + + # RDoc::RD::BlockParser for tmp src + @subparser = nil + + # which part is in now + @in_part = nil + @part_content = [] + + @in_verbatim = false + + @yydebug = true + + document = do_parse + + unless @footnotes.empty? then + blankline = document.parts.pop + + document.parts << RDoc::Markup::Rule.new(1) + document.parts.concat @footnotes + + document.parts.push blankline + end + + document +end + +## +# Returns the next token from the document + +def next_token # :nodoc: + # preprocessing + # if it is not in RD part + # => method + while @in_part != "rd" + line = @src[@i] + @i += 1 # next line + + case line + # src end + when false + return [false, false] + # RD part begin + when /^=begin\s*(?:\bRD\b.*)?\s*$/ + if @in_part # if in non-RD part + @part_content.push(line) + else + @in_part = "rd" + return [:WHITELINE, "=begin\n"] # <= for textblockand + end + # non-RD part begin + when /^=begin\s+(\w+)/ + part = $1 + if @in_part # if in non-RD part + @part_content.push(line) + else + @in_part = part if @tree.filter[part] # if filter exists +# p "BEGIN_PART: #{@in_part}" # DEBUG + end + # non-RD part end + when /^=end/ + if @in_part # if in non-RD part +# p "END_PART: #{@in_part}" # DEBUG + # make Part-in object + part = RDoc::RD::Part.new(@part_content.join(""), @tree, "r") + @part_content.clear + # call filter, part_out is output(Part object) + part_out = @tree.filter[@in_part].call(part) + + if @tree.filter[@in_part].mode == :rd # if output is RD formatted + subtree = parse_subtree(part_out.to_a) + else # if output is target formatted + basename = TMPFILE.join('.') + TMPFILE[-1] += 1 + tmpfile = open(@tree.tmp_dir + "/" + basename + ".#{@in_part}", "w") + tmpfile.print(part_out) + tmpfile.close + subtree = parse_subtree(["=begin\n", "<<< #{basename}\n", "=end\n"]) + end + @in_part = nil + return [:SUBTREE, subtree] + end + else + if @in_part # if in non-RD part + @part_content.push(line) + end + end + end + + @current_indent = @indent_stack.join("") + line = @src[@i] + case line + when false + if_current_indent_equal("") do + [false, false] + end + when /^=end/ + if_current_indent_equal("") do + @in_part = nil + [:WHITELINE, "=end"] # MUST CHANGE?? + end + when /^\s*$/ + @i += 1 # next line + return [:WHITELINE, ':WHITELINE'] + when /^\#/ # comment line + @i += 1 # next line + self.next_token() + when /^(={1,4})(?!=)\s*(?=\S)/, /^(\+{1,2})(?!\+)\s*(?=\S)/ + rest = $' # ' + rest.strip! + mark = $1 + if_current_indent_equal("") do + return [:HEADLINE, [MARK_TO_LEVEL[mark], rest]] + end + when /^<<<\s*(\S+)/ + file = $1 + if_current_indent_equal("") do + suffix = file[-3 .. -1] + if suffix == ".rd" or suffix == ".rb" + subtree = parse_subtree(get_included(file)) + [:SUBTREE, subtree] + else + [:INCLUDE, file] + end + end + when /^(\s*)\*(\s*)/ + rest = $' # ' + newIndent = $2 + if_current_indent_equal($1) do + if @in_verbatim + [:STRINGLINE, line] + else + @indent_stack.push("\s" << newIndent) + [:ITEMLISTLINE, rest] + end + end + when /^(\s*)(\(\d+\))(\s*)/ + rest = $' # ' + mark = $2 + newIndent = $3 + if_current_indent_equal($1) do + if @in_verbatim + [:STRINGLINE, line] + else + @indent_stack.push("\s" * mark.size << newIndent) + [:ENUMLISTLINE, rest] + end + end + when /^(\s*):(\s*)/ + rest = $' # ' + newIndent = $2 + if_current_indent_equal($1) do + if @in_verbatim + [:STRINGLINE, line] + else + @indent_stack.push("\s#{$2}") + [:DESCLISTLINE, rest] + end + end + when /^(\s*)---(?!-|\s*$)/ + indent = $1 + rest = $' + /\s*/ === rest + term = $' + new_indent = $& + if_current_indent_equal(indent) do + if @in_verbatim + [:STRINGLINE, line] + else + @indent_stack.push("\s\s\s" + new_indent) + [:METHODLISTLINE, term] + end + end + when /^(\s*)/ + if_current_indent_equal($1) do + [:STRINGLINE, line] + end + else + raise "[BUG] parsing error may occured." + end +end + +## +# Yields to the given block if +indent+ matches the current indent, otherwise +# an indentation token is processed. + +def if_current_indent_equal(indent) + indent = indent.sub(/\t/, "\s" * 8) + if @current_indent == indent + @i += 1 # next line + yield + elsif indent.index(@current_indent) == 0 + @indent_stack.push(indent[@current_indent.size .. -1]) + [:INDENT, ":INDENT"] + else + @indent_stack.pop + [:DEDENT, ":DEDENT"] + end +end +private :if_current_indent_equal + +## +# Cuts off excess whitespace in +src+ + +def cut_off(src) + ret = [] + whiteline_buf = [] + + line = src.shift + /^\s*/ =~ line + + indent = Regexp.quote($&) + ret.push($') + + while line = src.shift + if /^(\s*)$/ =~ line + whiteline_buf.push(line) + elsif /^#{indent}/ =~ line + unless whiteline_buf.empty? + ret.concat(whiteline_buf) + whiteline_buf.clear + end + ret.push($') + else + raise "[BUG]: probably Parser Error while cutting off.\n" + end + end + ret +end +private :cut_off + +def set_term_to_element(parent, term) +# parent.set_term_under_document_struct(term, @tree.document_struct) + parent.set_term_without_document_struct(term) +end +private :set_term_to_element + +## +# Raises a ParseError when invalid formatting is found + +def on_error(et, ev, _values) + prv, cur, nxt = format_line_num(@i, @i+1, @i+2) + + raise ParseError, <<Msg + +RD syntax error: line #{@i+1}: + #{prv} |#{@src[@i-1].chomp} + #{cur}=>|#{@src[@i].chomp} + #{nxt} |#{@src[@i+1].chomp} + +Msg +end + +## +# Current line number + +def line_index + @i +end + +## +# Parses subtree +src+ + +def parse_subtree src + @subparser ||= RDoc::RD::BlockParser.new + + @subparser.parse src +end +private :parse_subtree + +## +# Retrieves the content for +file+ from the include_path + +def get_included(file) + included = [] + + @include_path.each do |dir| + file_name = File.join dir, file + + if File.exist? file_name then + included = IO.readlines file_name + break + end + end + + included +end +private :get_included + +## +# Formats line numbers +line_numbers+ prettily + +def format_line_num(*line_numbers) + width = line_numbers.collect{|i| i.to_s.length }.max + line_numbers.collect{|i| sprintf("%#{width}d", i) } +end +private :format_line_num + +## +# Retrieves the content of +values+ as a single String + +def content values + values.map { |value| value.content }.join +end + +## +# Creates a paragraph for +value+ + +def paragraph value + content = cut_off(value).join(' ').rstrip + contents = @inline_parser.parse content + + RDoc::Markup::Paragraph.new(*contents) +end + +## +# Adds footnote +content+ to the document + +def add_footnote content + index = @footnotes.length / 2 + 1 + + footmark_link = "{^#{index}}[rdoc-label:footmark-#{index}:foottext-#{index}]" + + @footnotes << RDoc::Markup::Paragraph.new(footmark_link, ' ', *content) + @footnotes << RDoc::Markup::BlankLine.new + + index +end + +## +# Adds label +label+ to the document + +def add_label label + @labels[label] = true + + label +end + +# :stopdoc: + +##### State transition tables begin ### + +racc_action_table = [ + 34, 35, 30, 33, 14, 73, 38, 33, 76, 15, + 88, 34, 35, 30, 33, 40, 34, 35, 30, 33, + 40, 65, 34, 35, 30, 33, 14, 73, 77, 14, + 54, 15, 34, 35, 30, 33, 14, 9, 10, 11, + 12, 15, 34, 35, 30, 33, 14, 73, 81, 54, + 38, 15, 34, 35, 30, 33, 14, 73, 40, 67, + 83, 15, 34, 35, 30, 33, 14, 73, 54, 30, + 35, 15, 34, 35, 30, 33, 34, 47, 36, 14, + 59, 15, 34, 35, 30, 33, 14, 73, 38, nil, + nil, 15, 34, 35, 30, 33, nil, 47, nil, nil, + nil, 15, 34, 35, 30, 33, 14, 73, nil, nil, + nil, 15, 34, 35, 30, 33, 14, 73, nil, nil, + nil, 15, 34, 35, 30, 33, 14, 9, 10, 11, + 12, 15, 34, 35, 30, 33, 14, 73, nil, nil, + nil, 15, 34, 35, 30, 33, 14, 73, 61, 63, + nil, 15, nil, 62, 60, 61, 63, 61, 63, 14, + 62, 87, 62, nil, 79, 34, 35, 30, 33 ] + +racc_action_check = [ + 86, 86, 86, 86, 86, 86, 57, 31, 49, 86, + 86, 41, 41, 41, 41, 41, 15, 15, 15, 15, + 15, 41, 45, 45, 45, 45, 45, 45, 51, 34, + 54, 45, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 85, 85, 85, 85, 85, 85, 56, 33, + 58, 85, 79, 79, 79, 79, 79, 79, 62, 44, + 66, 79, 78, 78, 78, 78, 78, 78, 30, 28, + 25, 78, 24, 24, 24, 24, 22, 24, 1, 35, + 36, 24, 75, 75, 75, 75, 75, 75, 13, nil, + nil, 75, 27, 27, 27, 27, nil, 27, nil, nil, + nil, 27, 74, 74, 74, 74, 74, 74, nil, nil, + nil, 74, 68, 68, 68, 68, 68, 68, nil, nil, + nil, 68, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 46, 46, 46, 46, 46, 46, nil, nil, + nil, 46, 47, 47, 47, 47, 47, 47, 39, 39, + nil, 47, nil, 39, 39, 82, 82, 64, 64, 52, + 82, 82, 64, nil, 52, 20, 20, 20, 20 ] + +racc_action_pointer = [ + 29, 78, 119, nil, nil, nil, nil, nil, nil, nil, + nil, nil, nil, 81, nil, 13, nil, nil, nil, nil, + 162, nil, 73, nil, 69, 66, nil, 89, 64, nil, + 60, 1, nil, 41, 22, 72, 80, nil, nil, 141, + nil, 8, nil, nil, 46, 19, 129, 139, nil, -5, + nil, 15, 152, nil, 22, nil, 35, -1, 43, nil, + nil, nil, 51, nil, 150, nil, 47, nil, 109, nil, + nil, nil, nil, nil, 99, 79, nil, nil, 59, 49, + nil, nil, 148, nil, nil, 39, -3, nil, nil ] + +racc_action_default = [ + -2, -73, -1, -4, -5, -6, -7, -8, -9, -10, + -11, -12, -13, -14, -16, -73, -23, -24, -25, -26, + -27, -31, -32, -34, -72, -36, -38, -72, -40, -42, + -59, -44, -46, -59, -63, -65, -73, -3, -15, -73, + -22, -73, -30, -33, -73, -69, -70, -71, -37, -73, + -41, -73, -51, -58, -61, -45, -73, -62, -64, 89, + -17, -19, -73, -21, -18, -28, -73, -35, -66, -53, + -54, -55, -56, -57, -67, -68, -39, -43, -49, -73, + -60, -47, -73, -29, -52, -48, -73, -20, -50 ] + +racc_goto_table = [ + 4, 39, 4, 68, 74, 75, 5, 6, 5, 6, + 51, 42, 44, 56, 3, 49, 37, 57, 58, 41, + 43, 48, 84, 50, 66, 55, 1, 64, 84, 84, + 45, 46, 42, 45, 46, 2, 85, 86, 80, 84, + 84, nil, nil, nil, nil, nil, nil, nil, 82, nil, + nil, nil, 78 ] + +racc_goto_check = [ + 4, 10, 4, 31, 31, 31, 5, 6, 5, 6, + 27, 12, 21, 27, 3, 21, 3, 9, 9, 17, + 19, 23, 32, 26, 11, 29, 1, 10, 32, 32, + 5, 6, 12, 5, 6, 2, 31, 31, 33, 32, + 32, nil, nil, nil, nil, nil, nil, nil, 10, nil, + nil, nil, 4 ] + +racc_goto_pointer = [ + nil, 26, 35, 14, 0, 6, 7, nil, nil, -17, + -14, -17, -9, nil, nil, nil, nil, 4, nil, -2, + nil, -12, nil, -4, nil, nil, -5, -20, nil, -6, + nil, -42, -46, -16 ] + +racc_goto_default = [ + nil, nil, nil, nil, 70, 71, 72, 7, 8, 13, + nil, nil, 21, 16, 17, 18, 19, 20, 22, 23, + 24, nil, 25, 26, 27, 28, 29, nil, 31, 32, + 52, nil, 69, 53 ] + +racc_reduce_table = [ + 0, 0, :racc_error, + 1, 15, :_reduce_1, + 0, 15, :_reduce_2, + 2, 16, :_reduce_3, + 1, 16, :_reduce_4, + 1, 17, :_reduce_5, + 1, 17, :_reduce_6, + 1, 17, :_reduce_none, + 1, 17, :_reduce_8, + 1, 17, :_reduce_9, + 1, 17, :_reduce_10, + 1, 17, :_reduce_11, + 1, 21, :_reduce_12, + 1, 22, :_reduce_13, + 1, 18, :_reduce_14, + 2, 23, :_reduce_15, + 1, 23, :_reduce_16, + 3, 19, :_reduce_17, + 1, 25, :_reduce_18, + 2, 24, :_reduce_19, + 4, 24, :_reduce_20, + 2, 24, :_reduce_21, + 1, 24, :_reduce_22, + 1, 26, :_reduce_none, + 1, 26, :_reduce_none, + 1, 26, :_reduce_none, + 1, 26, :_reduce_none, + 1, 20, :_reduce_27, + 3, 20, :_reduce_28, + 4, 20, :_reduce_29, + 2, 31, :_reduce_30, + 1, 31, :_reduce_31, + 1, 27, :_reduce_32, + 2, 32, :_reduce_33, + 1, 32, :_reduce_34, + 3, 33, :_reduce_35, + 1, 28, :_reduce_36, + 2, 36, :_reduce_37, + 1, 36, :_reduce_38, + 3, 37, :_reduce_39, + 1, 29, :_reduce_40, + 2, 39, :_reduce_41, + 1, 39, :_reduce_42, + 3, 40, :_reduce_43, + 1, 30, :_reduce_44, + 2, 42, :_reduce_45, + 1, 42, :_reduce_46, + 3, 43, :_reduce_47, + 3, 41, :_reduce_48, + 2, 41, :_reduce_49, + 4, 41, :_reduce_50, + 1, 41, :_reduce_51, + 2, 45, :_reduce_52, + 1, 45, :_reduce_none, + 1, 46, :_reduce_54, + 1, 46, :_reduce_55, + 1, 46, :_reduce_none, + 1, 46, :_reduce_57, + 1, 44, :_reduce_none, + 0, 44, :_reduce_none, + 2, 47, :_reduce_none, + 1, 47, :_reduce_none, + 2, 34, :_reduce_62, + 1, 34, :_reduce_63, + 2, 38, :_reduce_64, + 1, 38, :_reduce_65, + 2, 35, :_reduce_66, + 2, 35, :_reduce_67, + 2, 35, :_reduce_68, + 1, 35, :_reduce_69, + 1, 35, :_reduce_none, + 1, 35, :_reduce_71, + 0, 35, :_reduce_72 ] + +racc_reduce_n = 73 + +racc_shift_n = 89 + +racc_token_table = { + false => 0, + :error => 1, + :DUMMY => 2, + :ITEMLISTLINE => 3, + :ENUMLISTLINE => 4, + :DESCLISTLINE => 5, + :METHODLISTLINE => 6, + :STRINGLINE => 7, + :WHITELINE => 8, + :SUBTREE => 9, + :HEADLINE => 10, + :INCLUDE => 11, + :INDENT => 12, + :DEDENT => 13 } + +racc_nt_base = 14 + +racc_use_result_var = true + +Racc_arg = [ + racc_action_table, + racc_action_check, + racc_action_default, + racc_action_pointer, + racc_goto_table, + racc_goto_check, + racc_goto_default, + racc_goto_pointer, + racc_nt_base, + racc_reduce_table, + racc_token_table, + racc_shift_n, + racc_reduce_n, + racc_use_result_var ] + +Racc_token_to_s_table = [ + "$end", + "error", + "DUMMY", + "ITEMLISTLINE", + "ENUMLISTLINE", + "DESCLISTLINE", + "METHODLISTLINE", + "STRINGLINE", + "WHITELINE", + "SUBTREE", + "HEADLINE", + "INCLUDE", + "INDENT", + "DEDENT", + "$start", + "document", + "blocks", + "block", + "textblock", + "verbatim", + "lists", + "headline", + "include", + "textblockcontent", + "verbatimcontent", + "verbatim_after_lists", + "list", + "itemlist", + "enumlist", + "desclist", + "methodlist", + "lists2", + "itemlistitems", + "itemlistitem", + "first_textblock_in_itemlist", + "other_blocks_in_list", + "enumlistitems", + "enumlistitem", + "first_textblock_in_enumlist", + "desclistitems", + "desclistitem", + "description_part", + "methodlistitems", + "methodlistitem", + "whitelines", + "blocks_in_list", + "block_in_list", + "whitelines2" ] + +Racc_debug_parser = false + +##### State transition tables end ##### + +# reduce 0 omitted + +def _reduce_1(val, _values, result) + result = RDoc::Markup::Document.new(*val[0]) + result +end + +def _reduce_2(val, _values, result) + raise ParseError, "file empty" + result +end + +def _reduce_3(val, _values, result) + result = val[0].concat val[1] + result +end + +def _reduce_4(val, _values, result) + result = val[0] + result +end + +def _reduce_5(val, _values, result) + result = val + result +end + +def _reduce_6(val, _values, result) + result = val + result +end + +# reduce 7 omitted + +def _reduce_8(val, _values, result) + result = val + result +end + +def _reduce_9(val, _values, result) + result = val + result +end + +def _reduce_10(val, _values, result) + result = [RDoc::Markup::BlankLine.new] + result +end + +def _reduce_11(val, _values, result) + result = val[0].parts + result +end + +def _reduce_12(val, _values, result) + # val[0] is like [level, title] + title = @inline_parser.parse(val[0][1]) + result = RDoc::Markup::Heading.new(val[0][0], title) + + result +end + +def _reduce_13(val, _values, result) + result = RDoc::Markup::Include.new val[0], @include_path + + result +end + +def _reduce_14(val, _values, result) + # val[0] is Array of String + result = paragraph val[0] + + result +end + +def _reduce_15(val, _values, result) + result << val[1].rstrip + result +end + +def _reduce_16(val, _values, result) + result = [val[0].rstrip] + result +end + +def _reduce_17(val, _values, result) + # val[1] is Array of String + content = cut_off val[1] + result = RDoc::Markup::Verbatim.new(*content) + + # imform to lexer. + @in_verbatim = false + + result +end + +def _reduce_18(val, _values, result) + # val[0] is Array of String + content = cut_off val[0] + result = RDoc::Markup::Verbatim.new(*content) + + # imform to lexer. + @in_verbatim = false + + result +end + +def _reduce_19(val, _values, result) + result << val[1] + + result +end + +def _reduce_20(val, _values, result) + result.concat val[2] + + result +end + +def _reduce_21(val, _values, result) + result << "\n" + + result +end + +def _reduce_22(val, _values, result) + result = val + # inform to lexer. + @in_verbatim = true + + result +end + +# reduce 23 omitted + +# reduce 24 omitted + +# reduce 25 omitted + +# reduce 26 omitted + +def _reduce_27(val, _values, result) + result = val[0] + + result +end + +def _reduce_28(val, _values, result) + result = val[1] + + result +end + +def _reduce_29(val, _values, result) + result = val[1].push(val[2]) + + result +end + +def _reduce_30(val, _values, result) + result = val[0] << val[1] + result +end + +def _reduce_31(val, _values, result) + result = [val[0]] + result +end + +def _reduce_32(val, _values, result) + result = RDoc::Markup::List.new :BULLET, *val[0] + + result +end + +def _reduce_33(val, _values, result) + result.push(val[1]) + result +end + +def _reduce_34(val, _values, result) + result = val + result +end + +def _reduce_35(val, _values, result) + result = RDoc::Markup::ListItem.new nil, val[0], *val[1] + + result +end + +def _reduce_36(val, _values, result) + result = RDoc::Markup::List.new :NUMBER, *val[0] + + result +end + +def _reduce_37(val, _values, result) + result.push(val[1]) + result +end + +def _reduce_38(val, _values, result) + result = val + result +end + +def _reduce_39(val, _values, result) + result = RDoc::Markup::ListItem.new nil, val[0], *val[1] + + result +end + +def _reduce_40(val, _values, result) + result = RDoc::Markup::List.new :NOTE, *val[0] + + result +end + +def _reduce_41(val, _values, result) + result.push(val[1]) + result +end + +def _reduce_42(val, _values, result) + result = val + result +end + +def _reduce_43(val, _values, result) + term = @inline_parser.parse val[0].strip + + result = RDoc::Markup::ListItem.new term, *val[1] + + result +end + +def _reduce_44(val, _values, result) + result = RDoc::Markup::List.new :LABEL, *val[0] + + result +end + +def _reduce_45(val, _values, result) + result.push(val[1]) + result +end + +def _reduce_46(val, _values, result) + result = val + result +end + +def _reduce_47(val, _values, result) + result = RDoc::Markup::ListItem.new "<tt>#{val[0].strip}</tt>", *val[1] + + result +end + +def _reduce_48(val, _values, result) + result = [val[1]].concat(val[2]) + + result +end + +def _reduce_49(val, _values, result) + result = [val[1]] + + result +end + +def _reduce_50(val, _values, result) + result = val[2] + + result +end + +def _reduce_51(val, _values, result) + result = [] + + result +end + +def _reduce_52(val, _values, result) + result.concat val[1] + result +end + +# reduce 53 omitted + +def _reduce_54(val, _values, result) + result = val + result +end + +def _reduce_55(val, _values, result) + result = val + result +end + +# reduce 56 omitted + +def _reduce_57(val, _values, result) + result = [] + result +end + +# reduce 58 omitted + +# reduce 59 omitted + +# reduce 60 omitted + +# reduce 61 omitted + +def _reduce_62(val, _values, result) + result = paragraph [val[0]].concat(val[1]) + + result +end + +def _reduce_63(val, _values, result) + result = paragraph [val[0]] + + result +end + +def _reduce_64(val, _values, result) + result = paragraph [val[0]].concat(val[1]) + + result +end + +def _reduce_65(val, _values, result) + result = paragraph [val[0]] + + result +end + +def _reduce_66(val, _values, result) + result = [val[0]].concat(val[1]) + + result +end + +def _reduce_67(val, _values, result) + result.concat val[1] + result +end + +def _reduce_68(val, _values, result) + result = val[1] + result +end + +def _reduce_69(val, _values, result) + result = val + result +end + +# reduce 70 omitted + +def _reduce_71(val, _values, result) + result = [] + result +end + +def _reduce_72(val, _values, result) + result = [] + result +end + +def _reduce_none(val, _values, result) + val[0] +end + +end # class BlockParser + +end diff --git a/jni/ruby/lib/rdoc/rd/inline.rb b/jni/ruby/lib/rdoc/rd/inline.rb new file mode 100644 index 0000000..ee724fb --- /dev/null +++ b/jni/ruby/lib/rdoc/rd/inline.rb @@ -0,0 +1,71 @@ +## +# Inline keeps track of markup and labels to create proper links. + +class RDoc::RD::Inline + + ## + # The text of the reference + + attr_reader :reference + + ## + # The markup of this reference in RDoc format + + attr_reader :rdoc + + ## + # Creates a new Inline for +rdoc+ and +reference+. + # + # +rdoc+ may be another Inline or a String. If +reference+ is not given it + # will use the text from +rdoc+. + + def self.new rdoc, reference = rdoc + if self === rdoc and reference.equal? rdoc then + rdoc + else + super + end + end + + ## + # Initializes the Inline with +rdoc+ and +inline+ + + def initialize rdoc, reference # :not-new: + @reference = reference.equal?(rdoc) ? reference.dup : reference + + # unpack + @reference = @reference.reference if self.class === @reference + @rdoc = rdoc + end + + def == other # :nodoc: + self.class === other and + @reference == other.reference and @rdoc == other.rdoc + end + + ## + # Appends +more+ to this inline. +more+ may be a String or another Inline. + + def append more + case more + when String then + @reference << more + @rdoc << more + when RDoc::RD::Inline then + @reference << more.reference + @rdoc << more.rdoc + else + raise "unknown thingy #{more}" + end + + self + end + + def inspect # :nodoc: + "(inline: #{self})" + end + + alias to_s rdoc # :nodoc: + +end + diff --git a/jni/ruby/lib/rdoc/rd/inline_parser.rb b/jni/ruby/lib/rdoc/rd/inline_parser.rb new file mode 100644 index 0000000..98b5035 --- /dev/null +++ b/jni/ruby/lib/rdoc/rd/inline_parser.rb @@ -0,0 +1,1207 @@ +# +# DO NOT MODIFY!!!! +# This file is automatically generated by Racc 1.4.12 +# from Racc grammer file "". +# + +require 'racc/parser.rb' + +require 'strscan' + +class RDoc::RD + +## +# RD format parser for inline markup such as emphasis, links, footnotes, etc. + +class InlineParser < Racc::Parser + + +# :stopdoc: + +EM_OPEN = '((*' +EM_OPEN_RE = /\A#{Regexp.quote(EM_OPEN)}/ +EM_CLOSE = '*))' +EM_CLOSE_RE = /\A#{Regexp.quote(EM_CLOSE)}/ +CODE_OPEN = '(({' +CODE_OPEN_RE = /\A#{Regexp.quote(CODE_OPEN)}/ +CODE_CLOSE = '}))' +CODE_CLOSE_RE = /\A#{Regexp.quote(CODE_CLOSE)}/ +VAR_OPEN = '((|' +VAR_OPEN_RE = /\A#{Regexp.quote(VAR_OPEN)}/ +VAR_CLOSE = '|))' +VAR_CLOSE_RE = /\A#{Regexp.quote(VAR_CLOSE)}/ +KBD_OPEN = '((%' +KBD_OPEN_RE = /\A#{Regexp.quote(KBD_OPEN)}/ +KBD_CLOSE = '%))' +KBD_CLOSE_RE = /\A#{Regexp.quote(KBD_CLOSE)}/ +INDEX_OPEN = '((:' +INDEX_OPEN_RE = /\A#{Regexp.quote(INDEX_OPEN)}/ +INDEX_CLOSE = ':))' +INDEX_CLOSE_RE = /\A#{Regexp.quote(INDEX_CLOSE)}/ +REF_OPEN = '((<' +REF_OPEN_RE = /\A#{Regexp.quote(REF_OPEN)}/ +REF_CLOSE = '>))' +REF_CLOSE_RE = /\A#{Regexp.quote(REF_CLOSE)}/ +FOOTNOTE_OPEN = '((-' +FOOTNOTE_OPEN_RE = /\A#{Regexp.quote(FOOTNOTE_OPEN)}/ +FOOTNOTE_CLOSE = '-))' +FOOTNOTE_CLOSE_RE = /\A#{Regexp.quote(FOOTNOTE_CLOSE)}/ +VERB_OPEN = "(('" +VERB_OPEN_RE = /\A#{Regexp.quote(VERB_OPEN)}/ +VERB_CLOSE = "'))" +VERB_CLOSE_RE = /\A#{Regexp.quote(VERB_CLOSE)}/ + +BAR = "|" +BAR_RE = /\A#{Regexp.quote(BAR)}/ +QUOTE = '"' +QUOTE_RE = /\A#{Regexp.quote(QUOTE)}/ +SLASH = "/" +SLASH_RE = /\A#{Regexp.quote(SLASH)}/ +BACK_SLASH = "\\" +BACK_SLASH_RE = /\A#{Regexp.quote(BACK_SLASH)}/ +URL = "URL:" +URL_RE = /\A#{Regexp.quote(URL)}/ + +other_re_mode = Regexp::EXTENDED +other_re_mode |= Regexp::MULTILINE + +OTHER_RE = Regexp.new( + "\\A.+?(?=#{Regexp.quote(EM_OPEN)}|#{Regexp.quote(EM_CLOSE)}| + #{Regexp.quote(CODE_OPEN)}|#{Regexp.quote(CODE_CLOSE)}| + #{Regexp.quote(VAR_OPEN)}|#{Regexp.quote(VAR_CLOSE)}| + #{Regexp.quote(KBD_OPEN)}|#{Regexp.quote(KBD_CLOSE)}| + #{Regexp.quote(INDEX_OPEN)}|#{Regexp.quote(INDEX_CLOSE)}| + #{Regexp.quote(REF_OPEN)}|#{Regexp.quote(REF_CLOSE)}| + #{Regexp.quote(FOOTNOTE_OPEN)}|#{Regexp.quote(FOOTNOTE_CLOSE)}| + #{Regexp.quote(VERB_OPEN)}|#{Regexp.quote(VERB_CLOSE)}| + #{Regexp.quote(BAR)}| + #{Regexp.quote(QUOTE)}| + #{Regexp.quote(SLASH)}| + #{Regexp.quote(BACK_SLASH)}| + #{Regexp.quote(URL)})", other_re_mode) + +# :startdoc: + +## +# Creates a new parser for inline markup in the rd format. The +block_parser+ +# is used to for footnotes and labels in the inline text. + +def initialize block_parser + @block_parser = block_parser +end + +## +# Parses the +inline+ text from RD format into RDoc format. + +def parse inline + @inline = inline + @src = StringScanner.new inline + @pre = "" + @yydebug = true + do_parse.to_s +end + +## +# Returns the next token from the inline text + +def next_token + return [false, false] if @src.eos? +# p @src.rest if @yydebug + if ret = @src.scan(EM_OPEN_RE) + @pre << ret + [:EM_OPEN, ret] + elsif ret = @src.scan(EM_CLOSE_RE) + @pre << ret + [:EM_CLOSE, ret] + elsif ret = @src.scan(CODE_OPEN_RE) + @pre << ret + [:CODE_OPEN, ret] + elsif ret = @src.scan(CODE_CLOSE_RE) + @pre << ret + [:CODE_CLOSE, ret] + elsif ret = @src.scan(VAR_OPEN_RE) + @pre << ret + [:VAR_OPEN, ret] + elsif ret = @src.scan(VAR_CLOSE_RE) + @pre << ret + [:VAR_CLOSE, ret] + elsif ret = @src.scan(KBD_OPEN_RE) + @pre << ret + [:KBD_OPEN, ret] + elsif ret = @src.scan(KBD_CLOSE_RE) + @pre << ret + [:KBD_CLOSE, ret] + elsif ret = @src.scan(INDEX_OPEN_RE) + @pre << ret + [:INDEX_OPEN, ret] + elsif ret = @src.scan(INDEX_CLOSE_RE) + @pre << ret + [:INDEX_CLOSE, ret] + elsif ret = @src.scan(REF_OPEN_RE) + @pre << ret + [:REF_OPEN, ret] + elsif ret = @src.scan(REF_CLOSE_RE) + @pre << ret + [:REF_CLOSE, ret] + elsif ret = @src.scan(FOOTNOTE_OPEN_RE) + @pre << ret + [:FOOTNOTE_OPEN, ret] + elsif ret = @src.scan(FOOTNOTE_CLOSE_RE) + @pre << ret + [:FOOTNOTE_CLOSE, ret] + elsif ret = @src.scan(VERB_OPEN_RE) + @pre << ret + [:VERB_OPEN, ret] + elsif ret = @src.scan(VERB_CLOSE_RE) + @pre << ret + [:VERB_CLOSE, ret] + elsif ret = @src.scan(BAR_RE) + @pre << ret + [:BAR, ret] + elsif ret = @src.scan(QUOTE_RE) + @pre << ret + [:QUOTE, ret] + elsif ret = @src.scan(SLASH_RE) + @pre << ret + [:SLASH, ret] + elsif ret = @src.scan(BACK_SLASH_RE) + @pre << ret + [:BACK_SLASH, ret] + elsif ret = @src.scan(URL_RE) + @pre << ret + [:URL, ret] + elsif ret = @src.scan(OTHER_RE) + @pre << ret + [:OTHER, ret] + else + ret = @src.rest + @pre << ret + @src.terminate + [:OTHER, ret] + end +end + +## +# Raises a ParseError when invalid formatting is found + +def on_error(et, ev, values) + lines_of_rest = @src.rest.lines.to_a.length + prev_words = prev_words_on_error(ev) + at = 4 + prev_words.length + + message = <<-MSG +RD syntax error: line #{@block_parser.line_index - lines_of_rest}: +...#{prev_words} #{(ev||'')} #{next_words_on_error()} ... + MSG + + message << " " * at + "^" * (ev ? ev.length : 0) + "\n" + raise ParseError, message +end + +## +# Returns words before the error + +def prev_words_on_error(ev) + pre = @pre + if ev and /#{Regexp.quote(ev)}$/ =~ pre + pre = $` + end + last_line(pre) +end + +## +# Returns the last line of +src+ + +def last_line(src) + if n = src.rindex("\n") + src[(n+1) .. -1] + else + src + end +end +private :last_line + +## +# Returns words following an error + +def next_words_on_error + if n = @src.rest.index("\n") + @src.rest[0 .. (n-1)] + else + @src.rest + end +end + +## +# Creates a new RDoc::RD::Inline for the +rdoc+ markup and the raw +reference+ + +def inline rdoc, reference = rdoc + RDoc::RD::Inline.new rdoc, reference +end + +# :stopdoc: +##### State transition tables begin ### + +racc_action_table = [ + 63, 64, 65, 153, 81, 62, 76, 78, 79, 87, + 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, + 77, 80, 152, 63, 64, 65, 61, 81, 62, 76, + 78, 79, 124, 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75, 77, 80, 149, 104, 103, 102, 100, + 101, 99, 115, 116, 117, 164, 105, 106, 107, 108, + 109, 110, 111, 112, 113, 114, 96, 118, 119, 104, + 103, 102, 100, 101, 99, 115, 116, 117, 89, 105, + 106, 107, 108, 109, 110, 111, 112, 113, 114, 88, + 118, 119, 104, 103, 102, 100, 101, 99, 115, 116, + 117, 161, 105, 106, 107, 108, 109, 110, 111, 112, + 113, 114, 86, 118, 119, 104, 103, 102, 100, 101, + 99, 115, 116, 117, 85, 105, 106, 107, 108, 109, + 110, 111, 112, 113, 114, 137, 118, 119, 63, 64, + 65, 61, 81, 62, 76, 78, 79, 84, 66, 67, + 68, 69, 70, 71, 72, 73, 74, 75, 77, 80, + 22, 23, 24, 25, 26, 21, 18, 19, 176, 177, + 13, 173, 14, 154, 15, 175, 16, 137, 17, 42, + 148, 20, 54, 38, 53, 55, 56, 57, 29, 13, + 177, 14, nil, 15, nil, 16, nil, 17, nil, nil, + 20, 22, 23, 24, 25, 26, 21, 18, 19, nil, + nil, 13, nil, 14, nil, 15, nil, 16, nil, 17, + nil, nil, 20, 22, 23, 24, 25, 26, 21, 18, + 19, nil, nil, 13, nil, 14, nil, 15, nil, 16, + nil, 17, nil, nil, 20, 22, 23, 24, 25, 26, + 21, 18, 19, nil, nil, 13, nil, 14, nil, 15, + nil, 16, nil, 17, 145, nil, 20, 54, 133, 53, + 55, 56, 57, nil, 13, nil, 14, nil, 15, nil, + 16, nil, 17, nil, nil, 20, 22, 23, 24, 25, + 26, 21, 18, 19, nil, nil, 13, nil, 14, nil, + 15, nil, 16, nil, 17, 145, nil, 20, 54, 133, + 53, 55, 56, 57, nil, 13, nil, 14, nil, 15, + nil, 16, nil, 17, nil, nil, 20, 22, 23, 24, + 25, 26, 21, 18, 19, nil, nil, 13, nil, 14, + nil, 15, nil, 16, nil, 17, 145, nil, 20, 54, + 133, 53, 55, 56, 57, nil, 13, nil, 14, nil, + 15, nil, 16, nil, 17, 145, nil, 20, 54, 133, + 53, 55, 56, 57, nil, 13, nil, 14, nil, 15, + nil, 16, nil, 17, nil, nil, 20, 22, 23, 24, + 25, 26, 21, 18, 19, nil, nil, 13, nil, 14, + nil, 15, nil, 16, 122, 17, nil, 54, 20, 53, + 55, 56, 57, nil, 13, nil, 14, nil, 15, nil, + 16, nil, 17, nil, nil, 20, 22, 23, 24, 25, + 26, 21, 18, 19, nil, nil, 13, nil, 14, nil, + 15, nil, 16, nil, 17, nil, nil, 20, 135, 136, + 54, 133, 53, 55, 56, 57, nil, 13, nil, 14, + nil, 15, nil, 16, nil, 17, nil, nil, 20, 135, + 136, 54, 133, 53, 55, 56, 57, nil, 13, nil, + 14, nil, 15, nil, 16, nil, 17, nil, nil, 20, + 135, 136, 54, 133, 53, 55, 56, 57, nil, 13, + nil, 14, nil, 15, nil, 16, nil, 17, nil, nil, + 20, 172, 135, 136, 54, 133, 53, 55, 56, 57, + 165, 135, 136, 54, 133, 53, 55, 56, 57, 95, + nil, nil, 54, 91, 53, 55, 56, 57, 174, 135, + 136, 54, 133, 53, 55, 56, 57, 158, nil, nil, + 54, nil, 53, 55, 56, 57, 178, 135, 136, 54, + 133, 53, 55, 56, 57, 145, nil, nil, 54, 133, + 53, 55, 56, 57, 145, nil, nil, 54, 133, 53, + 55, 56, 57, 135, 136, 54, 133, 53, 55, 56, + 57, 135, 136, 54, 133, 53, 55, 56, 57, 135, + 136, 54, 133, 53, 55, 56, 57, 22, 23, 24, + 25, 26, 21 ] + +racc_action_check = [ + 61, 61, 61, 61, 61, 61, 61, 61, 61, 33, + 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, + 61, 61, 61, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 41, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 125, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 97, 37, 97, 97, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 35, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 34, + 38, 38, 155, 155, 155, 155, 155, 155, 155, 155, + 155, 100, 155, 155, 155, 155, 155, 155, 155, 155, + 155, 155, 32, 155, 155, 91, 91, 91, 91, 91, + 91, 91, 91, 91, 31, 91, 91, 91, 91, 91, + 91, 91, 91, 91, 91, 43, 91, 91, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 29, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 17, 17, 17, 17, 17, 17, 17, 17, 165, 165, + 17, 162, 17, 90, 17, 164, 17, 94, 17, 18, + 58, 17, 18, 18, 18, 18, 18, 18, 1, 18, + 172, 18, nil, 18, nil, 18, nil, 18, nil, nil, + 18, 19, 19, 19, 19, 19, 19, 19, 19, nil, + nil, 19, nil, 19, nil, 19, nil, 19, nil, 19, + nil, nil, 19, 16, 16, 16, 16, 16, 16, 16, + 16, nil, nil, 16, nil, 16, nil, 16, nil, 16, + nil, 16, nil, nil, 16, 15, 15, 15, 15, 15, + 15, 15, 15, nil, nil, 15, nil, 15, nil, 15, + nil, 15, nil, 15, 45, nil, 15, 45, 45, 45, + 45, 45, 45, nil, 45, nil, 45, nil, 45, nil, + 45, nil, 45, nil, nil, 45, 14, 14, 14, 14, + 14, 14, 14, 14, nil, nil, 14, nil, 14, nil, + 14, nil, 14, nil, 14, 146, nil, 14, 146, 146, + 146, 146, 146, 146, nil, 146, nil, 146, nil, 146, + nil, 146, nil, 146, nil, nil, 146, 13, 13, 13, + 13, 13, 13, 13, 13, nil, nil, 13, nil, 13, + nil, 13, nil, 13, nil, 13, 138, nil, 13, 138, + 138, 138, 138, 138, 138, nil, 138, nil, 138, nil, + 138, nil, 138, nil, 138, 44, nil, 138, 44, 44, + 44, 44, 44, 44, nil, 44, nil, 44, nil, 44, + nil, 44, nil, 44, nil, nil, 44, 2, 2, 2, + 2, 2, 2, 2, 2, nil, nil, 2, nil, 2, + nil, 2, nil, 2, 39, 2, nil, 39, 2, 39, + 39, 39, 39, nil, 39, nil, 39, nil, 39, nil, + 39, nil, 39, nil, nil, 39, 0, 0, 0, 0, + 0, 0, 0, 0, nil, nil, 0, nil, 0, nil, + 0, nil, 0, nil, 0, nil, nil, 0, 122, 122, + 122, 122, 122, 122, 122, 122, nil, 122, nil, 122, + nil, 122, nil, 122, nil, 122, nil, nil, 122, 127, + 127, 127, 127, 127, 127, 127, 127, nil, 127, nil, + 127, nil, 127, nil, 127, nil, 127, nil, nil, 127, + 42, 42, 42, 42, 42, 42, 42, 42, nil, 42, + nil, 42, nil, 42, nil, 42, nil, 42, nil, nil, + 42, 159, 159, 159, 159, 159, 159, 159, 159, 159, + 126, 126, 126, 126, 126, 126, 126, 126, 126, 36, + nil, nil, 36, 36, 36, 36, 36, 36, 163, 163, + 163, 163, 163, 163, 163, 163, 163, 92, nil, nil, + 92, nil, 92, 92, 92, 92, 171, 171, 171, 171, + 171, 171, 171, 171, 171, 142, nil, nil, 142, 142, + 142, 142, 142, 142, 52, nil, nil, 52, 52, 52, + 52, 52, 52, 95, 95, 95, 95, 95, 95, 95, + 95, 168, 168, 168, 168, 168, 168, 168, 168, 158, + 158, 158, 158, 158, 158, 158, 158, 27, 27, 27, + 27, 27, 27 ] + +racc_action_pointer = [ + 423, 188, 384, nil, nil, nil, nil, nil, nil, nil, + nil, nil, nil, 324, 283, 242, 220, 157, 176, 198, + 135, nil, nil, nil, nil, nil, nil, 604, nil, 147, + nil, 110, 96, -9, 69, 56, 526, 43, 66, 401, + nil, 28, 486, 130, 362, 261, nil, nil, nil, nil, + nil, nil, 571, nil, nil, nil, nil, nil, 169, 20, + nil, -3, nil, nil, nil, nil, nil, nil, nil, nil, + nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, + nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, + 150, 112, 544, nil, 172, 579, nil, 43, nil, nil, + 95, nil, nil, nil, nil, nil, nil, nil, nil, nil, + nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, + nil, nil, 444, nil, nil, 52, 517, 465, nil, nil, + nil, nil, nil, nil, nil, nil, nil, nil, 343, nil, + nil, nil, 562, nil, nil, nil, 302, nil, nil, nil, + nil, nil, nil, nil, nil, 89, nil, nil, 595, 508, + nil, nil, 168, 535, 171, 164, nil, nil, 587, nil, + nil, 553, 185, nil, nil, nil, nil, nil, nil ] + +racc_action_default = [ + -138, -138, -1, -3, -4, -5, -6, -7, -8, -9, + -10, -11, -12, -138, -138, -138, -138, -138, -138, -138, + -138, -103, -104, -105, -106, -107, -108, -111, -110, -138, + -2, -138, -138, -138, -138, -138, -138, -138, -138, -27, + -26, -35, -138, -58, -41, -40, -47, -48, -49, -50, + -51, -52, -63, -66, -67, -68, -69, -70, -138, -138, + -112, -138, -116, -117, -118, -119, -120, -121, -122, -123, + -124, -125, -126, -127, -128, -129, -130, -131, -132, -133, + -134, -135, -137, -109, 179, -13, -14, -15, -16, -17, + -138, -138, -23, -22, -33, -138, -19, -24, -79, -80, + -138, -82, -83, -84, -85, -86, -87, -88, -89, -90, + -91, -92, -93, -94, -95, -96, -97, -98, -99, -100, + -25, -35, -138, -58, -28, -138, -59, -42, -46, -55, + -56, -65, -71, -72, -75, -76, -77, -31, -38, -44, + -53, -54, -57, -61, -73, -74, -39, -62, -101, -102, + -136, -113, -114, -115, -18, -20, -21, -33, -138, -138, + -78, -81, -138, -59, -36, -37, -64, -45, -59, -43, + -60, -138, -34, -36, -37, -29, -30, -32, -34 ] + +racc_goto_table = [ + 126, 44, 125, 43, 144, 144, 160, 93, 97, 52, + 166, 82, 144, 41, 40, 39, 138, 146, 169, 147, + 167, 94, 44, 1, 123, 129, 169, 52, 36, 37, + 52, 90, 59, 92, 121, 120, 31, 32, 33, 34, + 35, 170, 58, 166, 83, 30, 170, 166, 151, nil, + 150, nil, 166, 159, 8, 166, 8, nil, nil, nil, + nil, 155, nil, 156, 160, nil, nil, 8, 8, 8, + 8, 8, nil, 8, 4, nil, 4, 157, nil, nil, + 163, nil, 162, 52, nil, 168, nil, 4, 4, 4, + 4, 4, nil, 4, nil, nil, nil, nil, 144, nil, + nil, nil, 144, nil, nil, 129, 144, 144, nil, 5, + 129, 5, nil, nil, nil, nil, 171, 6, nil, 6, + nil, nil, 5, 5, 5, 5, 5, 11, 5, 11, + 6, 6, 6, 6, 6, 7, 6, 7, nil, nil, + 11, 11, 11, 11, 11, nil, 11, nil, 7, 7, + 7, 7, 7, nil, 7 ] + +racc_goto_check = [ + 22, 24, 21, 23, 36, 36, 37, 18, 16, 34, + 35, 41, 36, 20, 19, 17, 25, 25, 28, 32, + 29, 23, 24, 1, 23, 24, 28, 34, 13, 15, + 34, 14, 38, 17, 20, 19, 1, 1, 1, 1, + 1, 33, 1, 35, 39, 3, 33, 35, 42, nil, + 41, nil, 35, 22, 8, 35, 8, nil, nil, nil, + nil, 16, nil, 18, 37, nil, nil, 8, 8, 8, + 8, 8, nil, 8, 4, nil, 4, 23, nil, nil, + 22, nil, 21, 34, nil, 22, nil, 4, 4, 4, + 4, 4, nil, 4, nil, nil, nil, nil, 36, nil, + nil, nil, 36, nil, nil, 24, 36, 36, nil, 5, + 24, 5, nil, nil, nil, nil, 22, 6, nil, 6, + nil, nil, 5, 5, 5, 5, 5, 11, 5, 11, + 6, 6, 6, 6, 6, 7, 6, 7, nil, nil, + 11, 11, 11, 11, 11, nil, 11, nil, 7, 7, + 7, 7, 7, nil, 7 ] + +racc_goto_pointer = [ + nil, 23, nil, 43, 74, 109, 117, 135, 54, nil, + nil, 127, nil, 10, -5, 11, -30, -3, -29, -4, + -5, -40, -42, -15, -17, -28, nil, nil, -120, -107, + nil, nil, -33, -101, -9, -116, -40, -91, 12, 17, + nil, -9, -13 ] + +racc_goto_default = [ + nil, nil, 2, 3, 46, 47, 48, 49, 50, 9, + 10, 51, 12, nil, nil, nil, nil, nil, nil, nil, + nil, nil, nil, nil, 140, nil, 45, 127, 139, 128, + 141, 130, 142, 143, 132, 131, 134, 98, nil, 28, + 27, nil, 60 ] + +racc_reduce_table = [ + 0, 0, :racc_error, + 1, 27, :_reduce_none, + 2, 28, :_reduce_2, + 1, 28, :_reduce_3, + 1, 29, :_reduce_none, + 1, 29, :_reduce_none, + 1, 29, :_reduce_none, + 1, 29, :_reduce_none, + 1, 29, :_reduce_none, + 1, 29, :_reduce_none, + 1, 29, :_reduce_none, + 1, 29, :_reduce_none, + 1, 29, :_reduce_none, + 3, 30, :_reduce_13, + 3, 31, :_reduce_14, + 3, 32, :_reduce_15, + 3, 33, :_reduce_16, + 3, 34, :_reduce_17, + 4, 35, :_reduce_18, + 3, 35, :_reduce_19, + 2, 40, :_reduce_20, + 2, 40, :_reduce_21, + 1, 40, :_reduce_22, + 1, 40, :_reduce_23, + 2, 41, :_reduce_24, + 2, 41, :_reduce_25, + 1, 41, :_reduce_26, + 1, 41, :_reduce_27, + 2, 39, :_reduce_none, + 4, 39, :_reduce_29, + 4, 39, :_reduce_30, + 2, 43, :_reduce_31, + 4, 43, :_reduce_32, + 1, 44, :_reduce_33, + 3, 44, :_reduce_34, + 1, 45, :_reduce_none, + 3, 45, :_reduce_36, + 3, 45, :_reduce_37, + 2, 46, :_reduce_38, + 2, 46, :_reduce_39, + 1, 46, :_reduce_40, + 1, 46, :_reduce_41, + 1, 47, :_reduce_none, + 2, 51, :_reduce_43, + 1, 51, :_reduce_44, + 2, 53, :_reduce_45, + 1, 53, :_reduce_46, + 1, 50, :_reduce_none, + 1, 50, :_reduce_none, + 1, 50, :_reduce_none, + 1, 50, :_reduce_none, + 1, 50, :_reduce_none, + 1, 50, :_reduce_none, + 1, 54, :_reduce_none, + 1, 54, :_reduce_none, + 1, 55, :_reduce_none, + 1, 55, :_reduce_none, + 1, 56, :_reduce_57, + 1, 52, :_reduce_58, + 1, 57, :_reduce_59, + 2, 58, :_reduce_60, + 1, 58, :_reduce_none, + 2, 49, :_reduce_62, + 1, 49, :_reduce_none, + 2, 48, :_reduce_64, + 1, 48, :_reduce_none, + 1, 60, :_reduce_none, + 1, 60, :_reduce_none, + 1, 60, :_reduce_none, + 1, 60, :_reduce_none, + 1, 60, :_reduce_none, + 1, 62, :_reduce_none, + 1, 62, :_reduce_none, + 1, 59, :_reduce_none, + 1, 59, :_reduce_none, + 1, 61, :_reduce_none, + 1, 61, :_reduce_none, + 1, 61, :_reduce_none, + 2, 42, :_reduce_78, + 1, 42, :_reduce_none, + 1, 63, :_reduce_none, + 2, 63, :_reduce_none, + 1, 63, :_reduce_none, + 1, 63, :_reduce_none, + 1, 63, :_reduce_none, + 1, 63, :_reduce_none, + 1, 63, :_reduce_none, + 1, 63, :_reduce_none, + 1, 63, :_reduce_none, + 1, 63, :_reduce_none, + 1, 63, :_reduce_none, + 1, 63, :_reduce_none, + 1, 63, :_reduce_none, + 1, 63, :_reduce_none, + 1, 63, :_reduce_none, + 1, 63, :_reduce_none, + 1, 63, :_reduce_none, + 1, 63, :_reduce_none, + 1, 63, :_reduce_none, + 1, 63, :_reduce_none, + 1, 63, :_reduce_none, + 3, 36, :_reduce_101, + 3, 37, :_reduce_102, + 1, 65, :_reduce_none, + 1, 65, :_reduce_none, + 1, 65, :_reduce_none, + 1, 65, :_reduce_none, + 1, 65, :_reduce_none, + 1, 65, :_reduce_none, + 2, 66, :_reduce_109, + 1, 66, :_reduce_none, + 1, 38, :_reduce_111, + 1, 67, :_reduce_none, + 2, 67, :_reduce_113, + 2, 67, :_reduce_114, + 2, 67, :_reduce_115, + 1, 68, :_reduce_none, + 1, 68, :_reduce_none, + 1, 68, :_reduce_none, + 1, 68, :_reduce_none, + 1, 68, :_reduce_none, + 1, 68, :_reduce_none, + 1, 68, :_reduce_none, + 1, 68, :_reduce_none, + 1, 68, :_reduce_none, + 1, 68, :_reduce_none, + 1, 68, :_reduce_none, + 1, 68, :_reduce_none, + 1, 68, :_reduce_none, + 1, 68, :_reduce_none, + 1, 68, :_reduce_none, + 1, 68, :_reduce_none, + 1, 68, :_reduce_none, + 1, 68, :_reduce_none, + 1, 68, :_reduce_none, + 1, 68, :_reduce_none, + 2, 64, :_reduce_136, + 1, 64, :_reduce_none ] + +racc_reduce_n = 138 + +racc_shift_n = 179 + +racc_token_table = { + false => 0, + :error => 1, + :EX_LOW => 2, + :QUOTE => 3, + :BAR => 4, + :SLASH => 5, + :BACK_SLASH => 6, + :URL => 7, + :OTHER => 8, + :REF_OPEN => 9, + :FOOTNOTE_OPEN => 10, + :FOOTNOTE_CLOSE => 11, + :EX_HIGH => 12, + :EM_OPEN => 13, + :EM_CLOSE => 14, + :CODE_OPEN => 15, + :CODE_CLOSE => 16, + :VAR_OPEN => 17, + :VAR_CLOSE => 18, + :KBD_OPEN => 19, + :KBD_CLOSE => 20, + :INDEX_OPEN => 21, + :INDEX_CLOSE => 22, + :REF_CLOSE => 23, + :VERB_OPEN => 24, + :VERB_CLOSE => 25 } + +racc_nt_base = 26 + +racc_use_result_var = true + +Racc_arg = [ + racc_action_table, + racc_action_check, + racc_action_default, + racc_action_pointer, + racc_goto_table, + racc_goto_check, + racc_goto_default, + racc_goto_pointer, + racc_nt_base, + racc_reduce_table, + racc_token_table, + racc_shift_n, + racc_reduce_n, + racc_use_result_var ] + +Racc_token_to_s_table = [ + "$end", + "error", + "EX_LOW", + "QUOTE", + "BAR", + "SLASH", + "BACK_SLASH", + "URL", + "OTHER", + "REF_OPEN", + "FOOTNOTE_OPEN", + "FOOTNOTE_CLOSE", + "EX_HIGH", + "EM_OPEN", + "EM_CLOSE", + "CODE_OPEN", + "CODE_CLOSE", + "VAR_OPEN", + "VAR_CLOSE", + "KBD_OPEN", + "KBD_CLOSE", + "INDEX_OPEN", + "INDEX_CLOSE", + "REF_CLOSE", + "VERB_OPEN", + "VERB_CLOSE", + "$start", + "content", + "elements", + "element", + "emphasis", + "code", + "var", + "keyboard", + "index", + "reference", + "footnote", + "verb", + "normal_str_ele", + "substitute", + "ref_label", + "ref_label2", + "ref_url_strings", + "filename", + "element_label", + "element_label2", + "ref_subst_content", + "ref_subst_content_q", + "ref_subst_strings_q", + "ref_subst_strings_first", + "ref_subst_ele2", + "ref_subst_eles", + "ref_subst_str_ele_first", + "ref_subst_eles_q", + "ref_subst_ele", + "ref_subst_ele_q", + "ref_subst_str_ele", + "ref_subst_str_ele_q", + "ref_subst_strings", + "ref_subst_string3", + "ref_subst_string", + "ref_subst_string_q", + "ref_subst_string2", + "ref_url_string", + "verb_strings", + "normal_string", + "normal_strings", + "verb_string", + "verb_normal_string" ] + +Racc_debug_parser = false + +##### State transition tables end ##### + +# reduce 0 omitted + +# reduce 1 omitted + +def _reduce_2(val, _values, result) + result.append val[1] + result +end + +def _reduce_3(val, _values, result) + result = val[0] + result +end + +# reduce 4 omitted + +# reduce 5 omitted + +# reduce 6 omitted + +# reduce 7 omitted + +# reduce 8 omitted + +# reduce 9 omitted + +# reduce 10 omitted + +# reduce 11 omitted + +# reduce 12 omitted + +def _reduce_13(val, _values, result) + content = val[1] + result = inline "<em>#{content}</em>", content + + result +end + +def _reduce_14(val, _values, result) + content = val[1] + result = inline "<code>#{content}</code>", content + + result +end + +def _reduce_15(val, _values, result) + content = val[1] + result = inline "+#{content}+", content + + result +end + +def _reduce_16(val, _values, result) + content = val[1] + result = inline "<tt>#{content}</tt>", content + + result +end + +def _reduce_17(val, _values, result) + label = val[1] + @block_parser.add_label label.reference + result = "<span id=\"label-#{label}\">#{label}</span>" + + result +end + +def _reduce_18(val, _values, result) + result = "{#{val[1]}}[#{val[2].join}]" + + result +end + +def _reduce_19(val, _values, result) + scheme, inline = val[1] + + result = "{#{inline}}[#{scheme}#{inline.reference}]" + + result +end + +def _reduce_20(val, _values, result) + result = [nil, inline(val[1])] + + result +end + +def _reduce_21(val, _values, result) + result = [ + 'rdoc-label:', + inline("#{val[0].reference}/#{val[1].reference}") + ] + + result +end + +def _reduce_22(val, _values, result) + result = ['rdoc-label:', val[0].reference] + + result +end + +def _reduce_23(val, _values, result) + result = ['rdoc-label:', "#{val[0].reference}/"] + + result +end + +def _reduce_24(val, _values, result) + result = [nil, inline(val[1])] + + result +end + +def _reduce_25(val, _values, result) + result = [ + 'rdoc-label:', + inline("#{val[0].reference}/#{val[1].reference}") + ] + + result +end + +def _reduce_26(val, _values, result) + result = ['rdoc-label:', val[0]] + + result +end + +def _reduce_27(val, _values, result) + ref = val[0].reference + result = ['rdoc-label:', inline(ref, "#{ref}/")] + + result +end + +# reduce 28 omitted + +def _reduce_29(val, _values, result) + result = val[1] + result +end + +def _reduce_30(val, _values, result) + result = val[1] + result +end + +def _reduce_31(val, _values, result) + result = inline val[0] + + result +end + +def _reduce_32(val, _values, result) + result = inline "\"#{val[1]}\"" + + result +end + +def _reduce_33(val, _values, result) + result = inline val[0] + + result +end + +def _reduce_34(val, _values, result) + result = inline "\"#{val[1]}\"" + + result +end + +# reduce 35 omitted + +def _reduce_36(val, _values, result) + result = val[1] + result +end + +def _reduce_37(val, _values, result) + result = inline val[1] + result +end + +def _reduce_38(val, _values, result) + result = val[0].append val[1] + + result +end + +def _reduce_39(val, _values, result) + result = val[0].append val[1] + + result +end + +def _reduce_40(val, _values, result) + result = val[0] + + result +end + +def _reduce_41(val, _values, result) + result = inline val[0] + + result +end + +# reduce 42 omitted + +def _reduce_43(val, _values, result) + result = val[0].append val[1] + + result +end + +def _reduce_44(val, _values, result) + result = inline val[0] + + result +end + +def _reduce_45(val, _values, result) + result = val[0].append val[1] + + result +end + +def _reduce_46(val, _values, result) + result = val[0] + + result +end + +# reduce 47 omitted + +# reduce 48 omitted + +# reduce 49 omitted + +# reduce 50 omitted + +# reduce 51 omitted + +# reduce 52 omitted + +# reduce 53 omitted + +# reduce 54 omitted + +# reduce 55 omitted + +# reduce 56 omitted + +def _reduce_57(val, _values, result) + result = val[0] + + result +end + +def _reduce_58(val, _values, result) + result = inline val[0] + + result +end + +def _reduce_59(val, _values, result) + result = inline val[0] + + result +end + +def _reduce_60(val, _values, result) + result << val[1] + result +end + +# reduce 61 omitted + +def _reduce_62(val, _values, result) + result << val[1] + + result +end + +# reduce 63 omitted + +def _reduce_64(val, _values, result) + result << val[1] + + result +end + +# reduce 65 omitted + +# reduce 66 omitted + +# reduce 67 omitted + +# reduce 68 omitted + +# reduce 69 omitted + +# reduce 70 omitted + +# reduce 71 omitted + +# reduce 72 omitted + +# reduce 73 omitted + +# reduce 74 omitted + +# reduce 75 omitted + +# reduce 76 omitted + +# reduce 77 omitted + +def _reduce_78(val, _values, result) + result << val[1] + result +end + +# reduce 79 omitted + +# reduce 80 omitted + +# reduce 81 omitted + +# reduce 82 omitted + +# reduce 83 omitted + +# reduce 84 omitted + +# reduce 85 omitted + +# reduce 86 omitted + +# reduce 87 omitted + +# reduce 88 omitted + +# reduce 89 omitted + +# reduce 90 omitted + +# reduce 91 omitted + +# reduce 92 omitted + +# reduce 93 omitted + +# reduce 94 omitted + +# reduce 95 omitted + +# reduce 96 omitted + +# reduce 97 omitted + +# reduce 98 omitted + +# reduce 99 omitted + +# reduce 100 omitted + +def _reduce_101(val, _values, result) + index = @block_parser.add_footnote val[1].rdoc + result = "{*#{index}}[rdoc-label:foottext-#{index}:footmark-#{index}]" + + result +end + +def _reduce_102(val, _values, result) + result = inline "<tt>#{val[1]}</tt>", val[1] + + result +end + +# reduce 103 omitted + +# reduce 104 omitted + +# reduce 105 omitted + +# reduce 106 omitted + +# reduce 107 omitted + +# reduce 108 omitted + +def _reduce_109(val, _values, result) + result << val[1] + result +end + +# reduce 110 omitted + +def _reduce_111(val, _values, result) + result = inline val[0] + + result +end + +# reduce 112 omitted + +def _reduce_113(val, _values, result) + result = val[1] + result +end + +def _reduce_114(val, _values, result) + result = val[1] + result +end + +def _reduce_115(val, _values, result) + result = val[1] + result +end + +# reduce 116 omitted + +# reduce 117 omitted + +# reduce 118 omitted + +# reduce 119 omitted + +# reduce 120 omitted + +# reduce 121 omitted + +# reduce 122 omitted + +# reduce 123 omitted + +# reduce 124 omitted + +# reduce 125 omitted + +# reduce 126 omitted + +# reduce 127 omitted + +# reduce 128 omitted + +# reduce 129 omitted + +# reduce 130 omitted + +# reduce 131 omitted + +# reduce 132 omitted + +# reduce 133 omitted + +# reduce 134 omitted + +# reduce 135 omitted + +def _reduce_136(val, _values, result) + result << val[1] + result +end + +# reduce 137 omitted + +def _reduce_none(val, _values, result) + val[0] +end + +end # class InlineParser + +end diff --git a/jni/ruby/lib/rdoc/rdoc.rb b/jni/ruby/lib/rdoc/rdoc.rb new file mode 100644 index 0000000..4d45d47 --- /dev/null +++ b/jni/ruby/lib/rdoc/rdoc.rb @@ -0,0 +1,570 @@ +require 'rdoc' + +require 'find' +require 'fileutils' +require 'pathname' +require 'time' + +## +# This is the driver for generating RDoc output. It handles file parsing and +# generation of output. +# +# To use this class to generate RDoc output via the API, the recommended way +# is: +# +# rdoc = RDoc::RDoc.new +# options = rdoc.load_options # returns an RDoc::Options instance +# # set extra options +# rdoc.document options +# +# You can also generate output like the +rdoc+ executable: +# +# rdoc = RDoc::RDoc.new +# rdoc.document argv +# +# Where +argv+ is an array of strings, each corresponding to an argument you'd +# give rdoc on the command line. See <tt>rdoc --help<tt> for details. + +class RDoc::RDoc + + @current = nil + + ## + # This is the list of supported output generators + + GENERATORS = {} + + ## + # File pattern to exclude + + attr_accessor :exclude + + ## + # Generator instance used for creating output + + attr_accessor :generator + + ## + # Hash of files and their last modified times. + + attr_reader :last_modified + + ## + # RDoc options + + attr_accessor :options + + ## + # Accessor for statistics. Available after each call to parse_files + + attr_reader :stats + + ## + # The current documentation store + + attr_reader :store + + ## + # Add +klass+ that can generate output after parsing + + def self.add_generator(klass) + name = klass.name.sub(/^RDoc::Generator::/, '').downcase + GENERATORS[name] = klass + end + + ## + # Active RDoc::RDoc instance + + def self.current + @current + end + + ## + # Sets the active RDoc::RDoc instance + + def self.current= rdoc + @current = rdoc + end + + ## + # Creates a new RDoc::RDoc instance. Call #document to parse files and + # generate documentation. + + def initialize + @current = nil + @exclude = nil + @generator = nil + @last_modified = {} + @old_siginfo = nil + @options = nil + @stats = nil + @store = nil + end + + ## + # Report an error message and exit + + def error(msg) + raise RDoc::Error, msg + end + + ## + # Gathers a set of parseable files from the files and directories listed in + # +files+. + + def gather_files files + files = ["."] if files.empty? + + file_list = normalized_file_list files, true, @exclude + + file_list = file_list.uniq + + file_list = remove_unparseable file_list + + file_list.sort + end + + ## + # Turns RDoc from stdin into HTML + + def handle_pipe + @html = RDoc::Markup::ToHtml.new @options + + parser = RDoc::Text::MARKUP_FORMAT[@options.markup] + + document = parser.parse $stdin.read + + out = @html.convert document + + $stdout.write out + end + + ## + # Installs a siginfo handler that prints the current filename. + + def install_siginfo_handler + return unless Signal.list.include? 'INFO' + + @old_siginfo = trap 'INFO' do + puts @current if @current + end + end + + ## + # Loads options from .rdoc_options if the file exists, otherwise creates a + # new RDoc::Options instance. + + def load_options + options_file = File.expand_path '.rdoc_options' + return RDoc::Options.new unless File.exist? options_file + + RDoc.load_yaml + + parse_error = if Object.const_defined? :Psych then + Psych::SyntaxError + else + ArgumentError + end + + begin + options = YAML.load_file '.rdoc_options' + rescue *parse_error + end + + raise RDoc::Error, "#{options_file} is not a valid rdoc options file" unless + RDoc::Options === options + + options + end + + ## + # Create an output dir if it doesn't exist. If it does exist, but doesn't + # contain the flag file <tt>created.rid</tt> then we refuse to use it, as + # we may clobber some manually generated documentation + + def setup_output_dir(dir, force) + flag_file = output_flag_file dir + + last = {} + + if @options.dry_run then + # do nothing + elsif File.exist? dir then + error "#{dir} exists and is not a directory" unless File.directory? dir + + begin + open flag_file do |io| + unless force then + Time.parse io.gets + + io.each do |line| + file, time = line.split "\t", 2 + time = Time.parse(time) rescue next + last[file] = time + end + end + end + rescue SystemCallError, TypeError + error <<-ERROR + +Directory #{dir} already exists, but it looks like it isn't an RDoc directory. + +Because RDoc doesn't want to risk destroying any of your existing files, +you'll need to specify a different output directory name (using the --op <dir> +option) + + ERROR + end unless @options.force_output + else + FileUtils.mkdir_p dir + FileUtils.touch flag_file + end + + last + end + + ## + # Sets the current documentation tree to +store+ and sets the store's rdoc + # driver to this instance. + + def store= store + @store = store + @store.rdoc = self + end + + ## + # Update the flag file in an output directory. + + def update_output_dir(op_dir, time, last = {}) + return if @options.dry_run or not @options.update_output_dir + + open output_flag_file(op_dir), "w" do |f| + f.puts time.rfc2822 + last.each do |n, t| + f.puts "#{n}\t#{t.rfc2822}" + end + end + end + + ## + # Return the path name of the flag file in an output directory. + + def output_flag_file(op_dir) + File.join op_dir, "created.rid" + end + + ## + # The .document file contains a list of file and directory name patterns, + # representing candidates for documentation. It may also contain comments + # (starting with '#') + + def parse_dot_doc_file in_dir, filename + # read and strip comments + patterns = File.read(filename).gsub(/#.*/, '') + + result = [] + + patterns.split.each do |patt| + candidates = Dir.glob(File.join(in_dir, patt)) + result.concat normalized_file_list(candidates) + end + + result + end + + ## + # Given a list of files and directories, create a list of all the Ruby + # files they contain. + # + # If +force_doc+ is true we always add the given files, if false, only + # add files that we guarantee we can parse. It is true when looking at + # files given on the command line, false when recursing through + # subdirectories. + # + # The effect of this is that if you want a file with a non-standard + # extension parsed, you must name it explicitly. + + def normalized_file_list(relative_files, force_doc = false, + exclude_pattern = nil) + file_list = [] + + relative_files.each do |rel_file_name| + next if rel_file_name.end_with? 'created.rid' + next if exclude_pattern && exclude_pattern =~ rel_file_name + stat = File.stat rel_file_name rescue next + + case type = stat.ftype + when "file" then + next if last_modified = @last_modified[rel_file_name] and + stat.mtime.to_i <= last_modified.to_i + + if force_doc or RDoc::Parser.can_parse(rel_file_name) then + file_list << rel_file_name.sub(/^\.\//, '') + @last_modified[rel_file_name] = stat.mtime + end + when "directory" then + next if rel_file_name == "CVS" || rel_file_name == ".svn" + + created_rid = File.join rel_file_name, "created.rid" + next if File.file? created_rid + + dot_doc = File.join rel_file_name, RDoc::DOT_DOC_FILENAME + + if File.file? dot_doc then + file_list << parse_dot_doc_file(rel_file_name, dot_doc) + else + file_list << list_files_in_directory(rel_file_name) + end + else + warn "rdoc can't parse the #{type} #{rel_file_name}" + end + end + + file_list.flatten + end + + ## + # Return a list of the files to be processed in a directory. We know that + # this directory doesn't have a .document file, so we're looking for real + # files. However we may well contain subdirectories which must be tested + # for .document files. + + def list_files_in_directory dir + files = Dir.glob File.join(dir, "*") + + normalized_file_list files, false, @options.exclude + end + + ## + # Parses +filename+ and returns an RDoc::TopLevel + + def parse_file filename + if Object.const_defined? :Encoding then + encoding = @options.encoding + filename = filename.encode encoding + end + + @stats.add_file filename + + return if RDoc::Parser.binary? filename + + content = RDoc::Encoding.read_file filename, encoding + + return unless content + + filename_path = Pathname(filename).expand_path + relative_path = filename_path.relative_path_from @options.root + + if @options.page_dir and + relative_path.to_s.start_with? @options.page_dir.to_s then + relative_path = + relative_path.relative_path_from @options.page_dir + end + + top_level = @store.add_file filename, relative_path.to_s + + parser = RDoc::Parser.for top_level, filename, content, @options, @stats + + return unless parser + + parser.scan + + # restart documentation for the classes & modules found + top_level.classes_or_modules.each do |cm| + cm.done_documenting = false + end + + top_level + + rescue Errno::EACCES => e + $stderr.puts <<-EOF +Unable to read #{filename}, #{e.message} + +Please check the permissions for this file. Perhaps you do not have access to +it or perhaps the original author's permissions are to restrictive. If the +this is not your library please report a bug to the author. + EOF + rescue => e + $stderr.puts <<-EOF +Before reporting this, could you check that the file you're documenting +has proper syntax: + + #{Gem.ruby} -c #{filename} + +RDoc is not a full Ruby parser and will fail when fed invalid ruby programs. + +The internal error was: + +\t(#{e.class}) #{e.message} + + EOF + + $stderr.puts e.backtrace.join("\n\t") if $DEBUG_RDOC + + raise e + nil + end + + ## + # Parse each file on the command line, recursively entering directories. + + def parse_files files + file_list = gather_files files + @stats = RDoc::Stats.new @store, file_list.length, @options.verbosity + + return [] if file_list.empty? + + @stats.begin_adding + + file_info = file_list.map do |filename| + @current = filename + parse_file filename + end.compact + + @stats.done_adding + + file_info + end + + ## + # Removes file extensions known to be unparseable from +files+ and TAGS + # files for emacs and vim. + + def remove_unparseable files + files.reject do |file| + file =~ /\.(?:class|eps|erb|scpt\.txt|ttf|yml)$/i or + (file =~ /tags$/i and + open(file, 'rb') { |io| + io.read(100) =~ /\A(\f\n[^,]+,\d+$|!_TAG_)/ + }) + end + end + + ## + # Generates documentation or a coverage report depending upon the settings + # in +options+. + # + # +options+ can be either an RDoc::Options instance or an array of strings + # equivalent to the strings that would be passed on the command line like + # <tt>%w[-q -o doc -t My\ Doc\ Title]</tt>. #document will automatically + # call RDoc::Options#finish if an options instance was given. + # + # For a list of options, see either RDoc::Options or <tt>rdoc --help</tt>. + # + # By default, output will be stored in a directory called "doc" below the + # current directory, so make sure you're somewhere writable before invoking. + + def document options + self.store = RDoc::Store.new + + if RDoc::Options === options then + @options = options + @options.finish + else + @options = load_options + @options.parse options + end + + if @options.pipe then + handle_pipe + exit + end + + @exclude = @options.exclude + + unless @options.coverage_report then + @last_modified = setup_output_dir @options.op_dir, @options.force_update + end + + @store.encoding = @options.encoding if @options.respond_to? :encoding + @store.dry_run = @options.dry_run + @store.main = @options.main_page + @store.title = @options.title + @store.path = @options.op_dir + + @start_time = Time.now + + @store.load_cache + + file_info = parse_files @options.files + + @options.default_title = "RDoc Documentation" + + @store.complete @options.visibility + + @stats.coverage_level = @options.coverage_report + + if @options.coverage_report then + puts + + puts @stats.report.accept RDoc::Markup::ToRdoc.new + elsif file_info.empty? then + $stderr.puts "\nNo newer files." unless @options.quiet + else + gen_klass = @options.generator + + @generator = gen_klass.new @store, @options + + generate + end + + if @stats and (@options.coverage_report or not @options.quiet) then + puts + puts @stats.summary.accept RDoc::Markup::ToRdoc.new + end + + exit @stats.fully_documented? if @options.coverage_report + end + + ## + # Generates documentation for +file_info+ (from #parse_files) into the + # output dir using the generator selected + # by the RDoc options + + def generate + Dir.chdir @options.op_dir do + unless @options.quiet then + $stderr.puts "\nGenerating #{@generator.class.name.sub(/^.*::/, '')} format into #{Dir.pwd}..." + end + + @generator.generate + update_output_dir '.', @start_time, @last_modified + end + end + + ## + # Removes a siginfo handler and replaces the previous + + def remove_siginfo_handler + return unless Signal.list.key? 'INFO' + + handler = @old_siginfo || 'DEFAULT' + + trap 'INFO', handler + end + +end + +begin + require 'rubygems' + + if Gem.respond_to? :find_files then + rdoc_extensions = Gem.find_files 'rdoc/discover' + + rdoc_extensions.each do |extension| + begin + load extension + rescue => e + warn "error loading #{extension.inspect}: #{e.message} (#{e.class})" + warn "\t#{e.backtrace.join "\n\t"}" if $DEBUG + end + end + end +rescue LoadError +end + +# require built-in generators after discovery in case they've been replaced +require 'rdoc/generator/darkfish' +require 'rdoc/generator/ri' +require 'rdoc/generator/pot' + diff --git a/jni/ruby/lib/rdoc/require.rb b/jni/ruby/lib/rdoc/require.rb new file mode 100644 index 0000000..a3d4bd1 --- /dev/null +++ b/jni/ruby/lib/rdoc/require.rb @@ -0,0 +1,51 @@ +## +# A file loaded by \#require + +class RDoc::Require < RDoc::CodeObject + + ## + # Name of the required file + + attr_accessor :name + + ## + # Creates a new Require that loads +name+ with +comment+ + + def initialize(name, comment) + super() + @name = name.gsub(/'|"/, "") #' + @top_level = nil + self.comment = comment + end + + def inspect # :nodoc: + "#<%s:0x%x require '%s' in %s>" % [ + self.class, + object_id, + @name, + parent_file_name, + ] + end + + def to_s # :nodoc: + "require #{name} in: #{parent}" + end + + ## + # The RDoc::TopLevel corresponding to this require, or +nil+ if not found. + + def top_level + @top_level ||= begin + tl = RDoc::TopLevel.all_files_hash[name + '.rb'] + + if tl.nil? and RDoc::TopLevel.all_files.first.full_name =~ %r(^lib/) then + # second chance + tl = RDoc::TopLevel.all_files_hash['lib/' + name + '.rb'] + end + + tl + end + end + +end + diff --git a/jni/ruby/lib/rdoc/ri.rb b/jni/ruby/lib/rdoc/ri.rb new file mode 100644 index 0000000..8b35e0f --- /dev/null +++ b/jni/ruby/lib/rdoc/ri.rb @@ -0,0 +1,20 @@ +require 'rdoc' + +## +# Namespace for the ri command line tool's implementation. +# +# See <tt>ri --help</tt> for details. + +module RDoc::RI + + ## + # Base RI error class + + class Error < RDoc::Error; end + + autoload :Driver, 'rdoc/ri/driver' + autoload :Paths, 'rdoc/ri/paths' + autoload :Store, 'rdoc/ri/store' + +end + diff --git a/jni/ruby/lib/rdoc/ri/driver.rb b/jni/ruby/lib/rdoc/ri/driver.rb new file mode 100644 index 0000000..39064c1 --- /dev/null +++ b/jni/ruby/lib/rdoc/ri/driver.rb @@ -0,0 +1,1497 @@ +require 'abbrev' +require 'optparse' + +begin + require 'readline' +rescue LoadError +end + +begin + require 'win32console' +rescue LoadError +end + +require 'rdoc' + +## +# For RubyGems backwards compatibility + +require 'rdoc/ri/formatter' + +## +# The RI driver implements the command-line ri tool. +# +# The driver supports: +# * loading RI data from: +# * Ruby's standard library +# * RubyGems +# * ~/.rdoc +# * A user-supplied directory +# * Paging output (uses RI_PAGER environment variable, PAGER environment +# variable or the less, more and pager programs) +# * Interactive mode with tab-completion +# * Abbreviated names (ri Zl shows Zlib documentation) +# * Colorized output +# * Merging output from multiple RI data sources + +class RDoc::RI::Driver + + ## + # Base Driver error class + + class Error < RDoc::RI::Error; end + + ## + # Raised when a name isn't found in the ri data stores + + class NotFoundError < Error + + ## + # Name that wasn't found + + alias name message + + def message # :nodoc: + "Nothing known about #{super}" + end + end + + ## + # Show all method documentation following a class or module + + attr_accessor :show_all + + ## + # An RDoc::RI::Store for each entry in the RI path + + attr_accessor :stores + + ## + # Controls the user of the pager vs $stdout + + attr_accessor :use_stdout + + ## + # Default options for ri + + def self.default_options + options = {} + options[:interactive] = false + options[:profile] = false + options[:show_all] = false + options[:use_cache] = true + options[:use_stdout] = !$stdout.tty? + options[:width] = 72 + + # By default all standard paths are used. + options[:use_system] = true + options[:use_site] = true + options[:use_home] = true + options[:use_gems] = true + options[:extra_doc_dirs] = [] + + return options + end + + ## + # Dump +data_path+ using pp + + def self.dump data_path + require 'pp' + + open data_path, 'rb' do |io| + pp Marshal.load(io.read) + end + end + + ## + # Parses +argv+ and returns a Hash of options + + def self.process_args argv + options = default_options + + opts = OptionParser.new do |opt| + opt.accept File do |file,| + File.readable?(file) and not File.directory?(file) and file + end + + opt.program_name = File.basename $0 + opt.version = RDoc::VERSION + opt.release = nil + opt.summary_indent = ' ' * 4 + + opt.banner = <<-EOT +Usage: #{opt.program_name} [options] [names...] + +Where name can be: + + Class | Module | Module::Class + + Class::method | Class#method | Class.method | method + + gem_name: | gem_name:README | gem_name:History + +All class names may be abbreviated to their minimum unambiguous form. If a name +is ambiguous, all valid options will be listed. + +A '.' matches either class or instance methods, while #method +matches only instance and ::method matches only class methods. + +README and other files may be displayed by prefixing them with the gem name +they're contained in. If the gem name is followed by a ':' all files in the +gem will be shown. The file name extension may be omitted where it is +unambiguous. + +For example: + + #{opt.program_name} Fil + #{opt.program_name} File + #{opt.program_name} File.new + #{opt.program_name} zip + #{opt.program_name} rdoc:README + +Note that shell quoting or escaping may be required for method names containing +punctuation: + + #{opt.program_name} 'Array.[]' + #{opt.program_name} compact\\! + +To see the default directories ri will search, run: + + #{opt.program_name} --list-doc-dirs + +Specifying the --system, --site, --home, --gems or --doc-dir options will +limit ri to searching only the specified directories. + +ri options may be set in the 'RI' environment variable. + +The ri pager can be set with the 'RI_PAGER' environment variable or the +'PAGER' environment variable. + EOT + + opt.separator nil + opt.separator "Options:" + + opt.separator nil + + opt.on("--[no-]interactive", "-i", + "In interactive mode you can repeatedly", + "look up methods with autocomplete.") do |interactive| + options[:interactive] = interactive + end + + opt.separator nil + + opt.on("--[no-]all", "-a", + "Show all documentation for a class or", + "module.") do |show_all| + options[:show_all] = show_all + end + + opt.separator nil + + opt.on("--[no-]list", "-l", + "List classes ri knows about.") do |list| + options[:list] = list + end + + opt.separator nil + + opt.on("--[no-]pager", + "Send output directly to stdout,", + "rather than to a pager.") do |use_pager| + options[:use_stdout] = !use_pager + end + + opt.separator nil + + opt.on("-T", + "Synonym for --no-pager") do + options[:use_stdout] = true + end + + opt.separator nil + + opt.on("--width=WIDTH", "-w", OptionParser::DecimalInteger, + "Set the width of the output.") do |width| + options[:width] = width + end + + opt.separator nil + + opt.on("--server [PORT]", Integer, + "Run RDoc server on the given port.", + "The default port is 8214.") do |port| + options[:server] = port || 8214 + end + + opt.separator nil + + formatters = RDoc::Markup.constants.grep(/^To[A-Z][a-z]+$/).sort + formatters = formatters.sort.map do |formatter| + formatter.to_s.sub('To', '').downcase + end + formatters -= %w[html label test] # remove useless output formats + + opt.on("--format=NAME", "-f", + "Uses the selected formatter. The default", + "formatter is bs for paged output and ansi", + "otherwise. Valid formatters are:", + formatters.join(' '), formatters) do |value| + options[:formatter] = RDoc::Markup.const_get "To#{value.capitalize}" + end + + opt.separator nil + opt.separator "Data source options:" + opt.separator nil + + opt.on("--[no-]list-doc-dirs", + "List the directories from which ri will", + "source documentation on stdout and exit.") do |list_doc_dirs| + options[:list_doc_dirs] = list_doc_dirs + end + + opt.separator nil + + opt.on("--doc-dir=DIRNAME", "-d", Array, + "List of directories from which to source", + "documentation in addition to the standard", + "directories. May be repeated.") do |value| + value.each do |dir| + unless File.directory? dir then + raise OptionParser::InvalidArgument, "#{dir} is not a directory" + end + + options[:extra_doc_dirs] << File.expand_path(dir) + end + end + + opt.separator nil + + opt.on("--no-standard-docs", + "Do not include documentation from", + "the Ruby standard library, site_lib,", + "installed gems, or ~/.rdoc.", + "Use with --doc-dir") do + options[:use_system] = false + options[:use_site] = false + options[:use_gems] = false + options[:use_home] = false + end + + opt.separator nil + + opt.on("--[no-]system", + "Include documentation from Ruby's standard", + "library. Defaults to true.") do |value| + options[:use_system] = value + end + + opt.separator nil + + opt.on("--[no-]site", + "Include documentation from libraries", + "installed in site_lib.", + "Defaults to true.") do |value| + options[:use_site] = value + end + + opt.separator nil + + opt.on("--[no-]gems", + "Include documentation from RubyGems.", + "Defaults to true.") do |value| + options[:use_gems] = value + end + + opt.separator nil + + opt.on("--[no-]home", + "Include documentation stored in ~/.rdoc.", + "Defaults to true.") do |value| + options[:use_home] = value + end + + opt.separator nil + opt.separator "Debug options:" + opt.separator nil + + opt.on("--[no-]profile", + "Run with the ruby profiler") do |value| + options[:profile] = value + end + + opt.separator nil + + opt.on("--dump=CACHE", File, + "Dumps data from an ri cache or data file") do |value| + options[:dump_path] = value + end + end + + argv = ENV['RI'].to_s.split.concat argv + + opts.parse! argv + + options[:names] = argv + + options[:use_stdout] ||= !$stdout.tty? + options[:use_stdout] ||= options[:interactive] + options[:width] ||= 72 + + options + + rescue OptionParser::InvalidArgument, OptionParser::InvalidOption => e + puts opts + puts + puts e + exit 1 + end + + ## + # Runs the ri command line executable using +argv+ + + def self.run argv = ARGV + options = process_args argv + + if options[:dump_path] then + dump options[:dump_path] + return + end + + ri = new options + ri.run + end + + ## + # Creates a new driver using +initial_options+ from ::process_args + + def initialize initial_options = {} + @paging = false + @classes = nil + + options = self.class.default_options.update(initial_options) + + @formatter_klass = options[:formatter] + + require 'profile' if options[:profile] + + @names = options[:names] + @list = options[:list] + + @doc_dirs = [] + @stores = [] + + RDoc::RI::Paths.each(options[:use_system], options[:use_site], + options[:use_home], options[:use_gems], + *options[:extra_doc_dirs]) do |path, type| + @doc_dirs << path + + store = RDoc::RI::Store.new path, type + store.load_cache + @stores << store + end + + @list_doc_dirs = options[:list_doc_dirs] + + @interactive = options[:interactive] + @server = options[:server] + @use_stdout = options[:use_stdout] + @show_all = options[:show_all] + + # pager process for jruby + @jruby_pager_process = nil + end + + ## + # Adds paths for undocumented classes +also_in+ to +out+ + + def add_also_in out, also_in + return if also_in.empty? + + out << RDoc::Markup::Rule.new(1) + out << RDoc::Markup::Paragraph.new("Also found in:") + + paths = RDoc::Markup::Verbatim.new + also_in.each do |store| + paths.parts.push store.friendly_path, "\n" + end + out << paths + end + + ## + # Adds a class header to +out+ for class +name+ which is described in + # +classes+. + + def add_class out, name, classes + heading = if classes.all? { |klass| klass.module? } then + name + else + superclass = classes.map do |klass| + klass.superclass unless klass.module? + end.compact.shift || 'Object' + + superclass = superclass.full_name unless String === superclass + + "#{name} < #{superclass}" + end + + out << RDoc::Markup::Heading.new(1, heading) + out << RDoc::Markup::BlankLine.new + end + + ## + # Adds "(from ...)" to +out+ for +store+ + + def add_from out, store + out << RDoc::Markup::Paragraph.new("(from #{store.friendly_path})") + end + + ## + # Adds +extends+ to +out+ + + def add_extends out, extends + add_extension_modules out, 'Extended by', extends + end + + ## + # Adds a list of +extensions+ to this module of the given +type+ to +out+. + # add_includes and add_extends call this, so you should use those directly. + + def add_extension_modules out, type, extensions + return if extensions.empty? + + out << RDoc::Markup::Rule.new(1) + out << RDoc::Markup::Heading.new(1, "#{type}:") + + extensions.each do |modules, store| + if modules.length == 1 then + add_extension_modules_single out, store, modules.first + else + add_extension_modules_multiple out, store, modules + end + end + end + + ## + # Renders multiple included +modules+ from +store+ to +out+. + + def add_extension_modules_multiple out, store, modules # :nodoc: + out << RDoc::Markup::Paragraph.new("(from #{store.friendly_path})") + + wout, with = modules.partition { |incl| incl.comment.empty? } + + out << RDoc::Markup::BlankLine.new unless with.empty? + + with.each do |incl| + out << RDoc::Markup::Paragraph.new(incl.name) + out << RDoc::Markup::BlankLine.new + out << incl.comment + end + + unless wout.empty? then + verb = RDoc::Markup::Verbatim.new + + wout.each do |incl| + verb.push incl.name, "\n" + end + + out << verb + end + end + + ## + # Adds a single extension module +include+ from +store+ to +out+ + + def add_extension_modules_single out, store, include # :nodoc: + name = include.name + path = store.friendly_path + out << RDoc::Markup::Paragraph.new("#{name} (from #{path})") + + if include.comment then + out << RDoc::Markup::BlankLine.new + out << include.comment + end + end + + ## + # Adds +includes+ to +out+ + + def add_includes out, includes + add_extension_modules out, 'Includes', includes + end + + ## + # Looks up the method +name+ and adds it to +out+ + + def add_method out, name + filtered = lookup_method name + + method_out = method_document name, filtered + + out.concat method_out.parts + end + + ## + # Adds documentation for all methods in +klass+ to +out+ + + def add_method_documentation out, klass + klass.method_list.each do |method| + begin + add_method out, method.full_name + rescue NotFoundError + next + end + end + end + + ## + # Adds a list of +methods+ to +out+ with a heading of +name+ + + def add_method_list out, methods, name + return if methods.empty? + + out << RDoc::Markup::Heading.new(1, "#{name}:") + out << RDoc::Markup::BlankLine.new + + if @use_stdout and !@interactive then + out.concat methods.map { |method| + RDoc::Markup::Verbatim.new method + } + else + out << RDoc::Markup::IndentedParagraph.new(2, methods.join(', ')) + end + + out << RDoc::Markup::BlankLine.new + end + + ## + # Returns ancestor classes of +klass+ + + def ancestors_of klass + ancestors = [] + + unexamined = [klass] + seen = [] + + loop do + break if unexamined.empty? + current = unexamined.shift + seen << current + + stores = classes[current] + + break unless stores and not stores.empty? + + klasses = stores.map do |store| + store.ancestors[current] + end.flatten.uniq + + klasses = klasses - seen + + ancestors.concat klasses + unexamined.concat klasses + end + + ancestors.reverse + end + + ## + # For RubyGems backwards compatibility + + def class_cache # :nodoc: + end + + ## + # Builds a RDoc::Markup::Document from +found+, +klasess+ and +includes+ + + def class_document name, found, klasses, includes, extends + also_in = [] + + out = RDoc::Markup::Document.new + + add_class out, name, klasses + + add_includes out, includes + add_extends out, extends + + found.each do |store, klass| + render_class out, store, klass, also_in + end + + add_also_in out, also_in + + out + end + + ## + # Adds the class +comment+ to +out+. + + def class_document_comment out, comment # :nodoc: + unless comment.empty? then + out << RDoc::Markup::Rule.new(1) + + if comment.merged? then + parts = comment.parts + parts = parts.zip [RDoc::Markup::BlankLine.new] * parts.length + parts.flatten! + parts.pop + + out.concat parts + else + out << comment + end + end + end + + ## + # Adds the constants from +klass+ to the Document +out+. + + def class_document_constants out, klass # :nodoc: + return if klass.constants.empty? + + out << RDoc::Markup::Heading.new(1, "Constants:") + out << RDoc::Markup::BlankLine.new + list = RDoc::Markup::List.new :NOTE + + constants = klass.constants.sort_by { |constant| constant.name } + + list.items.concat constants.map { |constant| + parts = constant.comment.parts if constant.comment + parts << RDoc::Markup::Paragraph.new('[not documented]') if + parts.empty? + + RDoc::Markup::ListItem.new(constant.name, *parts) + } + + out << list + out << RDoc::Markup::BlankLine.new + end + + ## + # Hash mapping a known class or module to the stores it can be loaded from + + def classes + return @classes if @classes + + @classes = {} + + @stores.each do |store| + store.cache[:modules].each do |mod| + # using default block causes searched-for modules to be added + @classes[mod] ||= [] + @classes[mod] << store + end + end + + @classes + end + + ## + # Returns the stores wherein +name+ is found along with the classes, + # extends and includes that match it + + def classes_and_includes_and_extends_for name + klasses = [] + extends = [] + includes = [] + + found = @stores.map do |store| + begin + klass = store.load_class name + klasses << klass + extends << [klass.extends, store] if klass.extends + includes << [klass.includes, store] if klass.includes + [store, klass] + rescue RDoc::Store::MissingFileError + end + end.compact + + extends.reject! do |modules,| modules.empty? end + includes.reject! do |modules,| modules.empty? end + + [found, klasses, includes, extends] + end + + ## + # Completes +name+ based on the caches. For Readline + + def complete name + completions = [] + + klass, selector, method = parse_name name + + complete_klass name, klass, selector, method, completions + complete_method name, klass, selector, completions + + completions.sort.uniq + end + + def complete_klass name, klass, selector, method, completions # :nodoc: + klasses = classes.keys + + # may need to include Foo when given Foo:: + klass_name = method ? name : klass + + if name !~ /#|\./ then + completions.replace klasses.grep(/^#{Regexp.escape klass_name}[^:]*$/) + completions.concat klasses.grep(/^#{Regexp.escape name}[^:]*$/) if + name =~ /::$/ + + completions << klass if classes.key? klass # to complete a method name + elsif selector then + completions << klass if classes.key? klass + elsif classes.key? klass_name then + completions << klass_name + end + end + + def complete_method name, klass, selector, completions # :nodoc: + if completions.include? klass and name =~ /#|\.|::/ then + methods = list_methods_matching name + + if not methods.empty? then + # remove Foo if given Foo:: and a method was found + completions.delete klass + elsif selector then + # replace Foo with Foo:: as given + completions.delete klass + completions << "#{klass}#{selector}" + end + + completions.concat methods + end + end + + ## + # Converts +document+ to text and writes it to the pager + + def display document + page do |io| + text = document.accept formatter(io) + + io.write text + end + end + + ## + # Outputs formatted RI data for class +name+. Groups undocumented classes + + def display_class name + return if name =~ /#|\./ + + found, klasses, includes, extends = + classes_and_includes_and_extends_for name + + return if found.empty? + + out = class_document name, found, klasses, includes, extends + + display out + end + + ## + # Outputs formatted RI data for method +name+ + + def display_method name + out = RDoc::Markup::Document.new + + add_method out, name + + display out + end + + ## + # Outputs formatted RI data for the class or method +name+. + # + # Returns true if +name+ was found, false if it was not an alternative could + # be guessed, raises an error if +name+ couldn't be guessed. + + def display_name name + if name =~ /\w:(\w|$)/ then + display_page name + return true + end + + return true if display_class name + + display_method name if name =~ /::|#|\./ + + true + rescue NotFoundError + matches = list_methods_matching name if name =~ /::|#|\./ + matches = classes.keys.grep(/^#{Regexp.escape name}/) if matches.empty? + + raise if matches.empty? + + page do |io| + io.puts "#{name} not found, maybe you meant:" + io.puts + io.puts matches.sort.join("\n") + end + + false + end + + ## + # Displays each name in +name+ + + def display_names names + names.each do |name| + name = expand_name name + + display_name name + end + end + + ## + # Outputs formatted RI data for page +name+. + + def display_page name + store_name, page_name = name.split ':', 2 + + store = @stores.find { |s| s.source == store_name } + + return display_page_list store if page_name.empty? + + pages = store.cache[:pages] + + unless pages.include? page_name then + found_names = pages.select do |n| + n =~ /#{Regexp.escape page_name}\.[^.]+$/ + end + + if found_names.length.zero? then + return display_page_list store, pages + elsif found_names.length > 1 then + return display_page_list store, found_names, page_name + end + + page_name = found_names.first + end + + page = store.load_page page_name + + display page.comment + end + + ## + # Outputs a formatted RI page list for the pages in +store+. + + def display_page_list store, pages = store.cache[:pages], search = nil + out = RDoc::Markup::Document.new + + title = if search then + "#{search} pages" + else + 'Pages' + end + + out << RDoc::Markup::Heading.new(1, "#{title} in #{store.friendly_path}") + out << RDoc::Markup::BlankLine.new + + list = RDoc::Markup::List.new(:BULLET) + + pages.each do |page| + list << RDoc::Markup::Paragraph.new(page) + end + + out << list + + display out + end + + ## + # Expands abbreviated klass +klass+ into a fully-qualified class. "Zl::Da" + # will be expanded to Zlib::DataError. + + def expand_class klass + klass.split('::').inject '' do |expanded, klass_part| + expanded << '::' unless expanded.empty? + short = expanded << klass_part + + subset = classes.keys.select do |klass_name| + klass_name =~ /^#{expanded}[^:]*$/ + end + + abbrevs = Abbrev.abbrev subset + + expanded = abbrevs[short] + + raise NotFoundError, short unless expanded + + expanded.dup + end + end + + ## + # Expands the class portion of +name+ into a fully-qualified class. See + # #expand_class. + + def expand_name name + klass, selector, method = parse_name name + + return [selector, method].join if klass.empty? + + case selector + when ':' then + [find_store(klass), selector, method] + else + [expand_class(klass), selector, method] + end.join + end + + ## + # Filters the methods in +found+ trying to find a match for +name+. + + def filter_methods found, name + regexp = name_regexp name + + filtered = found.find_all do |store, methods| + methods.any? { |method| method.full_name =~ regexp } + end + + return filtered unless filtered.empty? + + found + end + + ## + # Yields items matching +name+ including the store they were found in, the + # class being searched for, the class they were found in (an ancestor) the + # types of methods to look up (from #method_type), and the method name being + # searched for + + def find_methods name + klass, selector, method = parse_name name + + types = method_type selector + + klasses = nil + ambiguous = klass.empty? + + if ambiguous then + klasses = classes.keys + else + klasses = ancestors_of klass + klasses.unshift klass + end + + methods = [] + + klasses.each do |ancestor| + ancestors = classes[ancestor] + + next unless ancestors + + klass = ancestor if ambiguous + + ancestors.each do |store| + methods << [store, klass, ancestor, types, method] + end + end + + methods = methods.sort_by do |_, k, a, _, m| + [k, a, m].compact + end + + methods.each do |item| + yield(*item) # :yields: store, klass, ancestor, types, method + end + + self + end + + ## + # Finds the given +pager+ for jruby. Returns an IO if +pager+ was found. + # + # Returns false if +pager+ does not exist. + # + # Returns nil if the jruby JVM doesn't support ProcessBuilder redirection + # (1.6 and older). + + def find_pager_jruby pager + require 'java' + require 'shellwords' + + return nil unless java.lang.ProcessBuilder.constants.include? :Redirect + + pager = Shellwords.split pager + + pb = java.lang.ProcessBuilder.new(*pager) + pb = pb.redirect_output java.lang.ProcessBuilder::Redirect::INHERIT + + @jruby_pager_process = pb.start + + input = @jruby_pager_process.output_stream + + io = input.to_io + io.sync = true + io + rescue java.io.IOException + false + end + + ## + # Finds a store that matches +name+ which can be the name of a gem, "ruby", + # "home" or "site". + # + # See also RDoc::Store#source + + def find_store name + @stores.each do |store| + source = store.source + + return source if source == name + + return source if + store.type == :gem and source =~ /^#{Regexp.escape name}-\d/ + end + + raise RDoc::RI::Driver::NotFoundError, name + end + + ## + # Creates a new RDoc::Markup::Formatter. If a formatter is given with -f, + # use it. If we're outputting to a pager, use bs, otherwise ansi. + + def formatter(io) + if @formatter_klass then + @formatter_klass.new + elsif paging? or !io.tty? then + RDoc::Markup::ToBs.new + else + RDoc::Markup::ToAnsi.new + end + end + + ## + # Runs ri interactively using Readline if it is available. + + def interactive + puts "\nEnter the method name you want to look up." + + if defined? Readline then + Readline.completion_proc = method :complete + puts "You can use tab to autocomplete." + end + + puts "Enter a blank line to exit.\n\n" + + loop do + name = if defined? Readline then + Readline.readline ">> " + else + print ">> " + $stdin.gets + end + + return if name.nil? or name.empty? + + name = expand_name name.strip + + begin + display_name name + rescue NotFoundError => e + puts e.message + end + end + + rescue Interrupt + exit + end + + ## + # Is +file+ in ENV['PATH']? + + def in_path? file + return true if file =~ %r%\A/% and File.exist? file + + ENV['PATH'].split(File::PATH_SEPARATOR).any? do |path| + File.exist? File.join(path, file) + end + end + + ## + # Lists classes known to ri starting with +names+. If +names+ is empty all + # known classes are shown. + + def list_known_classes names = [] + classes = [] + + stores.each do |store| + classes << store.module_names + end + + classes = classes.flatten.uniq.sort + + unless names.empty? then + filter = Regexp.union names.map { |name| /^#{name}/ } + + classes = classes.grep filter + end + + page do |io| + if paging? or io.tty? then + if names.empty? then + io.puts "Classes and Modules known to ri:" + else + io.puts "Classes and Modules starting with #{names.join ', '}:" + end + io.puts + end + + io.puts classes.join("\n") + end + end + + ## + # Returns an Array of methods matching +name+ + + def list_methods_matching name + found = [] + + find_methods name do |store, klass, ancestor, types, method| + if types == :instance or types == :both then + methods = store.instance_methods[ancestor] + + if methods then + matches = methods.grep(/^#{Regexp.escape method.to_s}/) + + matches = matches.map do |match| + "#{klass}##{match}" + end + + found.concat matches + end + end + + if types == :class or types == :both then + methods = store.class_methods[ancestor] + + next unless methods + matches = methods.grep(/^#{Regexp.escape method.to_s}/) + + matches = matches.map do |match| + "#{klass}::#{match}" + end + + found.concat matches + end + end + + found.uniq + end + + ## + # Loads RI data for method +name+ on +klass+ from +store+. +type+ and + # +cache+ indicate if it is a class or instance method. + + def load_method store, cache, klass, type, name + methods = store.send(cache)[klass] + + return unless methods + + method = methods.find do |method_name| + method_name == name + end + + return unless method + + store.load_method klass, "#{type}#{method}" + rescue RDoc::Store::MissingFileError => e + comment = RDoc::Comment.new("missing documentation at #{e.file}").parse + + method = RDoc::AnyMethod.new nil, name + method.comment = comment + method + end + + ## + # Returns an Array of RI data for methods matching +name+ + + def load_methods_matching name + found = [] + + find_methods name do |store, klass, ancestor, types, method| + methods = [] + + methods << load_method(store, :class_methods, ancestor, '::', method) if + [:class, :both].include? types + + methods << load_method(store, :instance_methods, ancestor, '#', method) if + [:instance, :both].include? types + + found << [store, methods.compact] + end + + found.reject do |path, methods| methods.empty? end + end + + ## + # Returns a filtered list of methods matching +name+ + + def lookup_method name + found = load_methods_matching name + + raise NotFoundError, name if found.empty? + + filter_methods found, name + end + + ## + # Builds a RDoc::Markup::Document from +found+, +klasses+ and +includes+ + + def method_document name, filtered + out = RDoc::Markup::Document.new + + out << RDoc::Markup::Heading.new(1, name) + out << RDoc::Markup::BlankLine.new + + filtered.each do |store, methods| + methods.each do |method| + render_method out, store, method, name + end + end + + out + end + + ## + # Returns the type of method (:both, :instance, :class) for +selector+ + + def method_type selector + case selector + when '.', nil then :both + when '#' then :instance + else :class + end + end + + ## + # Returns a regular expression for +name+ that will match an + # RDoc::AnyMethod's name. + + def name_regexp name + klass, type, name = parse_name name + + case type + when '#', '::' then + /^#{klass}#{type}#{Regexp.escape name}$/ + else + /^#{klass}(#|::)#{Regexp.escape name}$/ + end + end + + ## + # Paginates output through a pager program. + + def page + if pager = setup_pager then + begin + yield pager + ensure + pager.close + @jruby_pager_process.wait_for if @jruby_pager_process + end + else + yield $stdout + end + rescue Errno::EPIPE + ensure + @paging = false + end + + ## + # Are we using a pager? + + def paging? + @paging + end + + ## + # Extracts the class, selector and method name parts from +name+ like + # Foo::Bar#baz. + # + # NOTE: Given Foo::Bar, Bar is considered a class even though it may be a + # method + + def parse_name name + parts = name.split(/(::?|#|\.)/) + + if parts.length == 1 then + if parts.first =~ /^[a-z]|^([%&*+\/<>^`|~-]|\+@|-@|<<|<=>?|===?|=>|=~|>>|\[\]=?|~@)$/ then + type = '.' + meth = parts.pop + else + type = nil + meth = nil + end + elsif parts.length == 2 or parts.last =~ /::|#|\./ then + type = parts.pop + meth = nil + elsif parts[1] == ':' then + klass = parts.shift + type = parts.shift + meth = parts.join + elsif parts[-2] != '::' or parts.last !~ /^[A-Z]/ then + meth = parts.pop + type = parts.pop + end + + klass ||= parts.join + + [klass, type, meth] + end + + ## + # Renders the +klass+ from +store+ to +out+. If the klass has no + # documentable items the class is added to +also_in+ instead. + + def render_class out, store, klass, also_in # :nodoc: + comment = klass.comment + # TODO the store's cache should always return an empty Array + class_methods = store.class_methods[klass.full_name] || [] + instance_methods = store.instance_methods[klass.full_name] || [] + attributes = store.attributes[klass.full_name] || [] + + if comment.empty? and + instance_methods.empty? and class_methods.empty? then + also_in << store + return + end + + add_from out, store + + class_document_comment out, comment + + if class_methods or instance_methods or not klass.constants.empty? then + out << RDoc::Markup::Rule.new(1) + end + + class_document_constants out, klass + + add_method_list out, class_methods, 'Class methods' + add_method_list out, instance_methods, 'Instance methods' + add_method_list out, attributes, 'Attributes' + + add_method_documentation out, klass if @show_all + end + + def render_method out, store, method, name # :nodoc: + out << RDoc::Markup::Paragraph.new("(from #{store.friendly_path})") + + unless name =~ /^#{Regexp.escape method.parent_name}/ then + out << RDoc::Markup::Heading.new(3, "Implementation from #{method.parent_name}") + end + + out << RDoc::Markup::Rule.new(1) + + render_method_arguments out, method.arglists + render_method_superclass out, method + render_method_comment out, method + end + + def render_method_arguments out, arglists # :nodoc: + return unless arglists + + arglists = arglists.chomp.split "\n" + arglists = arglists.map { |line| line + "\n" } + out << RDoc::Markup::Verbatim.new(*arglists) + out << RDoc::Markup::Rule.new(1) + end + + def render_method_comment out, method # :nodoc: + out << RDoc::Markup::BlankLine.new + out << method.comment + out << RDoc::Markup::BlankLine.new + end + + def render_method_superclass out, method # :nodoc: + return unless + method.respond_to?(:superclass_method) and method.superclass_method + + out << RDoc::Markup::BlankLine.new + out << RDoc::Markup::Heading.new(4, "(Uses superclass method #{method.superclass_method})") + out << RDoc::Markup::Rule.new(1) + end + + ## + # Looks up and displays ri data according to the options given. + + def run + if @list_doc_dirs then + puts @doc_dirs + elsif @list then + list_known_classes @names + elsif @server then + start_server + elsif @interactive or @names.empty? then + interactive + else + display_names @names + end + rescue NotFoundError => e + abort e.message + end + + ## + # Sets up a pager program to pass output through. Tries the RI_PAGER and + # PAGER environment variables followed by pager, less then more. + + def setup_pager + return if @use_stdout + + jruby = Object.const_defined?(:RUBY_ENGINE) && RUBY_ENGINE == 'jruby' + + pagers = [ENV['RI_PAGER'], ENV['PAGER'], 'pager', 'less', 'more'] + + pagers.compact.uniq.each do |pager| + next unless pager + + pager_cmd = pager.split.first + + next unless in_path? pager_cmd + + if jruby then + case io = find_pager_jruby(pager) + when nil then break + when false then next + else io + end + else + io = IO.popen(pager, 'w') rescue next + end + + next if $? and $?.pid == io.pid and $?.exited? # pager didn't work + + @paging = true + + return io + end + + @use_stdout = true + + nil + end + + ## + # Starts a WEBrick server for ri. + + def start_server + require 'webrick' + + server = WEBrick::HTTPServer.new :Port => @server + + extra_doc_dirs = @stores.map {|s| s.type == :extra ? s.path : nil}.compact + + server.mount '/', RDoc::Servlet, nil, extra_doc_dirs + + trap 'INT' do server.shutdown end + trap 'TERM' do server.shutdown end + + server.start + end + +end + diff --git a/jni/ruby/lib/rdoc/ri/formatter.rb b/jni/ruby/lib/rdoc/ri/formatter.rb new file mode 100644 index 0000000..84d37a9 --- /dev/null +++ b/jni/ruby/lib/rdoc/ri/formatter.rb @@ -0,0 +1,5 @@ +## +# For RubyGems backwards compatibility + +module RDoc::RI::Formatter # :nodoc: +end diff --git a/jni/ruby/lib/rdoc/ri/paths.rb b/jni/ruby/lib/rdoc/ri/paths.rb new file mode 100644 index 0000000..970cb91 --- /dev/null +++ b/jni/ruby/lib/rdoc/ri/paths.rb @@ -0,0 +1,187 @@ +require 'rdoc/ri' + +## +# The directories where ri data lives. Paths can be enumerated via ::each, or +# queried individually via ::system_dir, ::site_dir, ::home_dir and ::gem_dir. + +module RDoc::RI::Paths + + #:stopdoc: + require 'rbconfig' + + version = RbConfig::CONFIG['ruby_version'] + + BASE = if RbConfig::CONFIG.key? 'ridir' then + File.join RbConfig::CONFIG['ridir'], version + else + File.join RbConfig::CONFIG['datadir'], 'ri', version + end + + homedir = begin + File.expand_path('~') + rescue ArgumentError + end + + homedir ||= ENV['HOME'] || + ENV['USERPROFILE'] || ENV['HOMEPATH'] # for 1.8 compatibility + + HOMEDIR = if homedir then + File.join homedir, ".rdoc" + end + #:startdoc: + + ## + # Iterates over each selected path yielding the directory and type. + # + # Yielded types: + # :system:: Where Ruby's ri data is stored. Yielded when +system+ is + # true + # :site:: Where ri for installed libraries are stored. Yielded when + # +site+ is true. Normally no ri data is stored here. + # :home:: ~/.rdoc. Yielded when +home+ is true. + # :gem:: ri data for an installed gem. Yielded when +gems+ is true. + # :extra:: ri data directory from the command line. Yielded for each + # entry in +extra_dirs+ + + def self.each system = true, site = true, home = true, gems = :latest, *extra_dirs # :yields: directory, type + return enum_for __method__, system, site, home, gems, *extra_dirs unless + block_given? + + extra_dirs.each do |dir| + yield dir, :extra + end + + yield system_dir, :system if system + yield site_dir, :site if site + yield home_dir, :home if home and HOMEDIR + + gemdirs(gems).each do |dir| + yield dir, :gem + end if gems + + nil + end + + ## + # The ri directory for the gem with +gem_name+. + + def self.gem_dir name, version + req = Gem::Requirement.new "= #{version}" + + spec = Gem::Specification.find_by_name name, req + + File.join spec.doc_dir, 'ri' + end + + ## + # The latest installed gems' ri directories. +filter+ can be :all or + # :latest. + # + # A +filter+ :all includes all versions of gems and includes gems without + # ri documentation. + + def self.gemdirs filter = :latest + require 'rubygems' unless defined?(Gem) + + ri_paths = {} + + all = Gem::Specification.map do |spec| + [File.join(spec.doc_dir, 'ri'), spec.name, spec.version] + end + + if filter == :all then + gemdirs = [] + + all.group_by do |_, name, _| + name + end.sort_by do |group, _| + group + end.map do |group, items| + items.sort_by do |_, _, version| + version + end.reverse_each do |dir,| + gemdirs << dir + end + end + + return gemdirs + end + + all.each do |dir, name, ver| + next unless File.exist? dir + + if ri_paths[name].nil? or ver > ri_paths[name].first then + ri_paths[name] = [ver, name, dir] + end + end + + ri_paths.sort_by { |_, (_, name, _)| name }.map { |k, v| v.last } + rescue LoadError + [] + end + + ## + # The location of the rdoc data in the user's home directory. + # + # Like ::system, ri data in the user's home directory is rare and predates + # libraries distributed via RubyGems. ri data is rarely generated into this + # directory. + + def self.home_dir + HOMEDIR + end + + ## + # Returns existing directories from the selected documentation directories + # as an Array. + # + # See also ::each + + def self.path(system = true, site = true, home = true, gems = :latest, *extra_dirs) + path = raw_path system, site, home, gems, *extra_dirs + + path.select { |directory| File.directory? directory } + end + + ## + # Returns selected documentation directories including nonexistent + # directories. + # + # See also ::each + + def self.raw_path(system, site, home, gems, *extra_dirs) + path = [] + + each(system, site, home, gems, *extra_dirs) do |dir, type| + path << dir + end + + path.compact + end + + ## + # The location of ri data installed into the site dir. + # + # Historically this was available for documentation installed by Ruby + # libraries predating RubyGems. It is unlikely to contain any content for + # modern Ruby installations. + + def self.site_dir + File.join BASE, 'site' + end + + ## + # The location of the built-in ri data. + # + # This data is built automatically when `make` is run when Ruby is + # installed. If you did not install Ruby by hand you may need to install + # the documentation yourself. Please consult the documentation for your + # package manager or Ruby installer for details. You can also use the + # rdoc-data gem to install system ri data for common versions of Ruby. + + def self.system_dir + File.join BASE, 'system' + end + +end + diff --git a/jni/ruby/lib/rdoc/ri/store.rb b/jni/ruby/lib/rdoc/ri/store.rb new file mode 100644 index 0000000..9fa9bbb --- /dev/null +++ b/jni/ruby/lib/rdoc/ri/store.rb @@ -0,0 +1,6 @@ +module RDoc::RI + + Store = RDoc::Store # :nodoc: + +end + diff --git a/jni/ruby/lib/rdoc/ri/task.rb b/jni/ruby/lib/rdoc/ri/task.rb new file mode 100644 index 0000000..e545d4a --- /dev/null +++ b/jni/ruby/lib/rdoc/ri/task.rb @@ -0,0 +1,71 @@ +require 'rubygems' +begin + gem 'rdoc' +rescue Gem::LoadError +end unless defined?(RDoc) + +require 'rdoc/task' + +## +# RDoc::RI::Task creates ri data in <code>./.rdoc</code> for your project. +# +# It contains the following tasks: +# +# [ri] +# Build ri data +# +# [clobber_ri] +# Delete ri data files. This target is automatically added to the main +# clobber target. +# +# [reri] +# Rebuild the ri data from scratch even if they are not out of date. +# +# Simple example: +# +# require 'rdoc/ri/task' +# +# RDoc::RI::Task.new do |ri| +# ri.main = 'README.rdoc' +# ri.rdoc_files.include 'README.rdoc', 'lib/**/*.rb' +# end +# +# For further configuration details see RDoc::Task. + +class RDoc::RI::Task < RDoc::Task + + DEFAULT_NAMES = { # :nodoc: + :clobber_rdoc => :clobber_ri, + :rdoc => :ri, + :rerdoc => :reri, + } + + ## + # Create an ri task with the given name. See RDoc::Task for documentation on + # setting names. + + def initialize name = DEFAULT_NAMES # :yield: self + super + end + + def clobber_task_description # :nodoc: + "Remove RI data files" + end + + ## + # Sets default task values + + def defaults + super + + @rdoc_dir = '.rdoc' + end + + def rdoc_task_description # :nodoc: + 'Build RI data files' + end + + def rerdoc_task_description # :nodoc: + 'Rebuild RI data files' + end +end diff --git a/jni/ruby/lib/rdoc/ruby_lex.rb b/jni/ruby/lib/rdoc/ruby_lex.rb new file mode 100644 index 0000000..91b90ab --- /dev/null +++ b/jni/ruby/lib/rdoc/ruby_lex.rb @@ -0,0 +1,1377 @@ +# coding: US-ASCII + +#-- +# irb/ruby-lex.rb - ruby lexcal analyzer +# $Release Version: 0.9.5$ +# $Revision: 17979 $ +# $Date: 2008-07-09 10:17:05 -0700 (Wed, 09 Jul 2008) $ +# by Keiju ISHITSUKA(keiju@ruby-lang.org) +# +#++ + +require "e2mmap" +require "irb/slex" +require "stringio" + +## +# Ruby lexer adapted from irb. +# +# The internals are not documented because they are scary. + +class RDoc::RubyLex + + ## + # Raised upon invalid input + + class Error < RDoc::Error + end + + # :stopdoc: + + extend Exception2MessageMapper + + def_exception(:AlreadyDefinedToken, "Already defined token(%s)") + def_exception(:TkReading2TokenNoKey, "key nothing(key='%s')") + def_exception(:TkSymbol2TokenNoKey, "key nothing(key='%s')") + def_exception(:TkReading2TokenDuplicateError, + "key duplicate(token_n='%s', key='%s')") + def_exception(:SyntaxError, "%s") + + def_exception(:TerminateLineInput, "Terminate Line Input") + + include RDoc::RubyToken + include IRB + + attr_accessor :continue + attr_accessor :lex_state + attr_reader :reader + + class << self + attr_accessor :debug_level + end + + def self.debug? + @debug_level > 0 + end + + self.debug_level = 0 + + # :startdoc: + + ## + # Returns an Array of +ruby+ tokens. See ::new for a description of + # +options+. + + def self.tokenize ruby, options + tokens = [] + + scanner = RDoc::RubyLex.new ruby, options + scanner.exception_on_syntax_error = true + + while token = scanner.token do + tokens << token + end + + tokens + end + + ## + # Creates a new lexer for +content+. +options+ is an RDoc::Options, only + # +tab_width is used. + + def initialize(content, options) + lex_init + + if /\t/ =~ content then + tab_width = options.tab_width + content = content.split(/\n/).map do |line| + 1 while line.gsub!(/\t+/) { + ' ' * (tab_width*$&.length - $`.length % tab_width) + } && $~ + line + end.join("\n") + end + + content << "\n" unless content[-1, 1] == "\n" + + set_input StringIO.new content + + @base_char_no = 0 + @char_no = 0 + @exp_line_no = @line_no = 1 + @here_readed = [] + @readed = [] + @rests = [] + @seek = 0 + + @here_header = false + @indent = 0 + @indent_stack = [] + @lex_state = :EXPR_BEG + @space_seen = false + + @continue = false + @line = "" + + @skip_space = false + @readed_auto_clean_up = false + @exception_on_syntax_error = true + + @prompt = nil + @prev_seek = nil + @ltype = nil + end + + # :stopdoc: + + def inspect # :nodoc: + "#<%s:0x%x pos %d lex_state %p space_seen %p>" % [ + self.class, object_id, + @io.pos, @lex_state, @space_seen, + ] + end + + attr_accessor :skip_space + attr_accessor :readed_auto_clean_up + attr_accessor :exception_on_syntax_error + + attr_reader :seek + attr_reader :char_no + attr_reader :line_no + attr_reader :indent + + # io functions + def set_input(io, p = nil, &block) + @io = io + if p.respond_to?(:call) + @input = p + elsif block_given? + @input = block + else + @input = Proc.new{@io.gets} + end + end + + def get_readed + if idx = @readed.rindex("\n") + @base_char_no = @readed.size - (idx + 1) + else + @base_char_no += @readed.size + end + + readed = @readed.join("") + @readed = [] + readed + end + + def getc + while @rests.empty? + # return nil unless buf_input + @rests.push nil unless buf_input + end + c = @rests.shift + if @here_header + @here_readed.push c + else + @readed.push c + end + @seek += 1 + if c == "\n" + @line_no += 1 + @char_no = 0 + else + @char_no += 1 + end + + c + end + + def gets + l = "" + while c = getc + l.concat(c) + break if c == "\n" + end + return nil if l == "" and c.nil? + l + end + + def eof? + @io.eof? + end + + def getc_of_rests + if @rests.empty? + nil + else + getc + end + end + + def ungetc(c = nil) + if @here_readed.empty? + c2 = @readed.pop + else + c2 = @here_readed.pop + end + c = c2 unless c + @rests.unshift c #c = + @seek -= 1 + if c == "\n" + @line_no -= 1 + if idx = @readed.rindex("\n") + @char_no = idx + 1 + else + @char_no = @base_char_no + @readed.size + end + else + @char_no -= 1 + end + end + + def peek_equal?(str) + chrs = str.split(//) + until @rests.size >= chrs.size + return false unless buf_input + end + @rests[0, chrs.size] == chrs + end + + def peek_match?(regexp) + while @rests.empty? + return false unless buf_input + end + regexp =~ @rests.join("") + end + + def peek(i = 0) + while @rests.size <= i + return nil unless buf_input + end + @rests[i] + end + + def buf_input + prompt + line = @input.call + return nil unless line + @rests.concat line.split(//) + true + end + private :buf_input + + def set_prompt(p = nil, &block) + p = block if block_given? + if p.respond_to?(:call) + @prompt = p + else + @prompt = Proc.new{print p} + end + end + + def prompt + if @prompt + @prompt.call(@ltype, @indent, @continue, @line_no) + end + end + + def initialize_input + @ltype = nil + @quoted = nil + @indent = 0 + @indent_stack = [] + @lex_state = :EXPR_BEG + @space_seen = false + @here_header = false + + @continue = false + prompt + + @line = "" + @exp_line_no = @line_no + end + + def each_top_level_statement + initialize_input + catch(:TERM_INPUT) do + loop do + begin + @continue = false + prompt + unless l = lex + throw :TERM_INPUT if @line == '' + else + #p l + @line.concat l + if @ltype or @continue or @indent > 0 + next + end + end + if @line != "\n" + yield @line, @exp_line_no + end + break unless l + @line = '' + @exp_line_no = @line_no + + @indent = 0 + @indent_stack = [] + prompt + rescue TerminateLineInput + initialize_input + prompt + get_readed + end + end + end + end + + def lex + until (((tk = token).kind_of?(TkNL) || tk.kind_of?(TkEND_OF_SCRIPT)) && + !@continue or + tk.nil?) + #p tk + #p @lex_state + #p self + end + line = get_readed + # print self.inspect + if line == "" and tk.kind_of?(TkEND_OF_SCRIPT) || tk.nil? + nil + else + line + end + end + + def token + # require "tracer" + # Tracer.on + @prev_seek = @seek + @prev_line_no = @line_no + @prev_char_no = @char_no + begin + begin + tk = @OP.match(self) + @space_seen = tk.kind_of?(TkSPACE) + rescue SyntaxError => e + raise Error, "syntax error: #{e.message}" if + @exception_on_syntax_error + + tk = TkError.new(@seek, @line_no, @char_no) + end + end while @skip_space and tk.kind_of?(TkSPACE) + + if @readed_auto_clean_up + get_readed + end + # Tracer.off + tk + end + + ENINDENT_CLAUSE = [ + "case", "class", "def", "do", "for", "if", + "module", "unless", "until", "while", "begin" #, "when" + ] + + DEINDENT_CLAUSE = ["end" #, "when" + ] + + PERCENT_LTYPE = { + "q" => "\'", + "Q" => "\"", + "x" => "\`", + "r" => "/", + "w" => "]", + "W" => "]", + "s" => ":" + } + + PERCENT_PAREN = { + "{" => "}", + "[" => "]", + "<" => ">", + "(" => ")" + } + + PERCENT_PAREN_REV = PERCENT_PAREN.invert + + Ltype2Token = { + "\'" => TkSTRING, + "\"" => TkSTRING, + "\`" => TkXSTRING, + "/" => TkREGEXP, + "]" => TkDSTRING, + ":" => TkSYMBOL + } + DLtype2Token = { + "\"" => TkDSTRING, + "\`" => TkDXSTRING, + "/" => TkDREGEXP, + } + + def lex_init() + @OP = IRB::SLex.new + @OP.def_rules("\0", "\004", "\032") do |op, io| + Token(TkEND_OF_SCRIPT, '') + end + + @OP.def_rules(" ", "\t", "\f", "\r", "\13") do |op, io| + @space_seen = true + str = op + while (ch = getc) =~ /[ \t\f\r\13]/ do + str << ch + end + ungetc + Token TkSPACE, str + end + + @OP.def_rule("#") do |op, io| + identify_comment + end + + @OP.def_rule("=begin", + proc{|op, io| @prev_char_no == 0 && peek(0) =~ /\s/}) do + |op, io| + @ltype = "=" + res = '' + nil until getc == "\n" + + until ( peek_equal?("=end") && peek(4) =~ /\s/ ) do + (ch = getc) + res << ch + end + + gets # consume =end + + @ltype = nil + Token(TkRD_COMMENT, res) + end + + @OP.def_rule("\n") do |op, io| + print "\\n\n" if RDoc::RubyLex.debug? + case @lex_state + when :EXPR_BEG, :EXPR_FNAME, :EXPR_DOT + @continue = true + else + @continue = false + @lex_state = :EXPR_BEG + until (@indent_stack.empty? || + [TkLPAREN, TkLBRACK, TkLBRACE, + TkfLPAREN, TkfLBRACK, TkfLBRACE].include?(@indent_stack.last)) + @indent_stack.pop + end + end + @here_header = false + @here_readed = [] + Token(TkNL) + end + + @OP.def_rules("*", "**", + "=", "==", "===", + "=~", "<=>", + "<", "<=", + ">", ">=", ">>") do + |op, io| + case @lex_state + when :EXPR_FNAME, :EXPR_DOT + @lex_state = :EXPR_ARG + else + @lex_state = :EXPR_BEG + end + Token(op) + end + + @OP.def_rules("!", "!=", "!~") do + |op, io| + @lex_state = :EXPR_BEG + Token(op) + end + + @OP.def_rules("<<") do + |op, io| + tk = nil + if @lex_state != :EXPR_END && @lex_state != :EXPR_CLASS && + (@lex_state != :EXPR_ARG || @space_seen) + c = peek(0) + if /\S/ =~ c && (/["'`]/ =~ c || /\w/ =~ c || c == "-") + tk = identify_here_document + end + end + unless tk + tk = Token(op) + case @lex_state + when :EXPR_FNAME, :EXPR_DOT + @lex_state = :EXPR_ARG + else + @lex_state = :EXPR_BEG + end + end + tk + end + + @OP.def_rules("'", '"') do + |op, io| + identify_string(op) + end + + @OP.def_rules("`") do + |op, io| + if @lex_state == :EXPR_FNAME + @lex_state = :EXPR_END + Token(op) + else + identify_string(op) + end + end + + @OP.def_rules('?') do + |op, io| + if @lex_state == :EXPR_END + @lex_state = :EXPR_BEG + Token(TkQUESTION) + else + ch = getc + if @lex_state == :EXPR_ARG && ch =~ /\s/ + ungetc + @lex_state = :EXPR_BEG; + Token(TkQUESTION) + else + @lex_state = :EXPR_END + Token(TkCHAR, "?#{ch}") + end + end + end + + @OP.def_rules("&", "&&", "|", "||") do + |op, io| + @lex_state = :EXPR_BEG + Token(op) + end + + @OP.def_rules("+=", "-=", "*=", "**=", + "&=", "|=", "^=", "<<=", ">>=", "||=", "&&=") do + |op, io| + @lex_state = :EXPR_BEG + op =~ /^(.*)=$/ + Token(TkOPASGN, $1) + end + + @OP.def_rule("+@", proc{|op, io| @lex_state == :EXPR_FNAME}) do + |op, io| + @lex_state = :EXPR_ARG + Token(op) + end + + @OP.def_rule("-@", proc{|op, io| @lex_state == :EXPR_FNAME}) do + |op, io| + @lex_state = :EXPR_ARG + Token(op) + end + + @OP.def_rules("+", "-") do + |op, io| + catch(:RET) do + if @lex_state == :EXPR_ARG + if @space_seen and peek(0) =~ /[0-9]/ + throw :RET, identify_number(op) + else + @lex_state = :EXPR_BEG + end + elsif @lex_state != :EXPR_END and peek(0) =~ /[0-9]/ + throw :RET, identify_number(op) + else + @lex_state = :EXPR_BEG + end + Token(op) + end + end + + @OP.def_rule(".") do + |op, io| + @lex_state = :EXPR_BEG + if peek(0) =~ /[0-9]/ + ungetc + identify_number + else + # for "obj.if" etc. + @lex_state = :EXPR_DOT + Token(TkDOT) + end + end + + @OP.def_rules("..", "...") do + |op, io| + @lex_state = :EXPR_BEG + Token(op) + end + + lex_int2 + end + + def lex_int2 + @OP.def_rules("]", "}", ")") do + |op, io| + @lex_state = :EXPR_END + @indent -= 1 + @indent_stack.pop + Token(op) + end + + @OP.def_rule(":") do + |op, io| + if @lex_state == :EXPR_END || peek(0) =~ /\s/ + @lex_state = :EXPR_BEG + Token(TkCOLON) + else + @lex_state = :EXPR_FNAME; + Token(TkSYMBEG) + end + end + + @OP.def_rule("::") do + |op, io| + # p @lex_state.id2name, @space_seen + if @lex_state == :EXPR_BEG or @lex_state == :EXPR_ARG && @space_seen + @lex_state = :EXPR_BEG + Token(TkCOLON3) + else + @lex_state = :EXPR_DOT + Token(TkCOLON2) + end + end + + @OP.def_rule("/") do + |op, io| + if @lex_state == :EXPR_BEG || @lex_state == :EXPR_MID + identify_string(op) + elsif peek(0) == '=' + getc + @lex_state = :EXPR_BEG + Token(TkOPASGN, "/") #/) + elsif @lex_state == :EXPR_ARG and @space_seen and peek(0) !~ /\s/ + identify_string(op) + else + @lex_state = :EXPR_BEG + Token("/") #/) + end + end + + @OP.def_rules("^") do + |op, io| + @lex_state = :EXPR_BEG + Token("^") + end + + # @OP.def_rules("^=") do + # @lex_state = :EXPR_BEG + # Token(OP_ASGN, :^) + # end + + @OP.def_rules(",") do + |op, io| + @lex_state = :EXPR_BEG + Token(op) + end + + @OP.def_rules(";") do + |op, io| + @lex_state = :EXPR_BEG + until (@indent_stack.empty? || + [TkLPAREN, TkLBRACK, TkLBRACE, + TkfLPAREN, TkfLBRACK, TkfLBRACE].include?(@indent_stack.last)) + @indent_stack.pop + end + Token(op) + end + + @OP.def_rule("~") do + |op, io| + @lex_state = :EXPR_BEG + Token("~") + end + + @OP.def_rule("~@", proc{|op, io| @lex_state == :EXPR_FNAME}) do + |op, io| + @lex_state = :EXPR_BEG + Token("~") + end + + @OP.def_rule("(") do + |op, io| + @indent += 1 + if @lex_state == :EXPR_BEG || @lex_state == :EXPR_MID + @lex_state = :EXPR_BEG + tk_c = TkfLPAREN + else + @lex_state = :EXPR_BEG + tk_c = TkLPAREN + end + @indent_stack.push tk_c + Token tk_c + end + + @OP.def_rule("[]", proc{|op, io| @lex_state == :EXPR_FNAME}) do + |op, io| + @lex_state = :EXPR_ARG + Token("[]") + end + + @OP.def_rule("[]=", proc{|op, io| @lex_state == :EXPR_FNAME}) do + |op, io| + @lex_state = :EXPR_ARG + Token("[]=") + end + + @OP.def_rule("[") do + |op, io| + @indent += 1 + if @lex_state == :EXPR_FNAME + tk_c = TkfLBRACK + else + if @lex_state == :EXPR_BEG || @lex_state == :EXPR_MID + tk_c = TkLBRACK + elsif @lex_state == :EXPR_ARG && @space_seen + tk_c = TkLBRACK + else + tk_c = TkfLBRACK + end + @lex_state = :EXPR_BEG + end + @indent_stack.push tk_c + Token(tk_c) + end + + @OP.def_rule("{") do + |op, io| + @indent += 1 + if @lex_state != :EXPR_END && @lex_state != :EXPR_ARG + tk_c = TkLBRACE + else + tk_c = TkfLBRACE + end + @lex_state = :EXPR_BEG + @indent_stack.push tk_c + Token(tk_c) + end + + @OP.def_rule('\\') do + |op, io| + if getc == "\n" + @space_seen = true + @continue = true + Token(TkSPACE) + else + ungetc + Token("\\") + end + end + + @OP.def_rule('%') do + |op, io| + if @lex_state == :EXPR_BEG || @lex_state == :EXPR_MID + identify_quotation + elsif peek(0) == '=' + getc + Token(TkOPASGN, :%) + elsif @lex_state == :EXPR_ARG and @space_seen and peek(0) !~ /\s/ + identify_quotation + else + @lex_state = :EXPR_BEG + Token("%") #)) + end + end + + @OP.def_rule('$') do + |op, io| + identify_gvar + end + + @OP.def_rule('@') do + |op, io| + if peek(0) =~ /[\w@]/ + ungetc + identify_identifier + else + Token("@") + end + end + + # @OP.def_rule("def", proc{|op, io| /\s/ =~ io.peek(0)}) do + # |op, io| + # @indent += 1 + # @lex_state = :EXPR_FNAME + # # @lex_state = :EXPR_END + # # until @rests[0] == "\n" or @rests[0] == ";" + # # rests.shift + # # end + # end + + @OP.def_rule("_") do + if peek_match?(/_END__/) and @lex_state == :EXPR_BEG then + 6.times { getc } + Token(TkEND_OF_SCRIPT, '__END__') + else + ungetc + identify_identifier + end + end + + @OP.def_rule("") do + |op, io| + printf "MATCH: start %s: %s\n", op, io.inspect if RDoc::RubyLex.debug? + if peek(0) =~ /[0-9]/ + t = identify_number + else + t = identify_identifier + end + printf "MATCH: end %s: %s\n", op, io.inspect if RDoc::RubyLex.debug? + t + end + + p @OP if RDoc::RubyLex.debug? + end + + def identify_gvar + @lex_state = :EXPR_END + + case ch = getc + when /[~_*$?!@\/\\;,=:<>".]/ #" + Token(TkGVAR, "$" + ch) + when "-" + Token(TkGVAR, "$-" + getc) + when "&", "`", "'", "+" + Token(TkBACK_REF, "$"+ch) + when /[1-9]/ + ref = ch + while (ch = getc) =~ /[0-9]/ do ref << ch end + ungetc + Token(TkNTH_REF, "$#{ref}") + when /\w/ + ungetc + ungetc + identify_identifier + else + ungetc + Token("$") + end + end + + IDENT_RE = if defined? Encoding then + eval '/[\w\u{0080}-\u{FFFFF}]/u' # 1.8 can't parse \u{} + else + /[\w\x80-\xFF]/ + end + + def identify_identifier + token = "" + if peek(0) =~ /[$@]/ + token.concat(c = getc) + if c == "@" and peek(0) == "@" + token.concat getc + end + end + + while (ch = getc) =~ IDENT_RE do + print " :#{ch}: " if RDoc::RubyLex.debug? + token.concat ch + end + + ungetc + + if (ch == "!" || ch == "?") && token[0,1] =~ /\w/ && peek(0) != "=" + token.concat getc + end + + # almost fix token + + case token + when /^\$/ + return Token(TkGVAR, token) + when /^\@\@/ + @lex_state = :EXPR_END + # p Token(TkCVAR, token) + return Token(TkCVAR, token) + when /^\@/ + @lex_state = :EXPR_END + return Token(TkIVAR, token) + end + + if @lex_state != :EXPR_DOT + print token, "\n" if RDoc::RubyLex.debug? + + token_c, *trans = TkReading2Token[token] + if token_c + # reserved word? + + if (@lex_state != :EXPR_BEG && + @lex_state != :EXPR_FNAME && + trans[1]) + # modifiers + token_c = TkSymbol2Token[trans[1]] + @lex_state = trans[0] + else + if @lex_state != :EXPR_FNAME + if ENINDENT_CLAUSE.include?(token) + valid = peek(0) != ':' + + # check for ``class = val'' etc. + case token + when "class" + valid = false unless peek_match?(/^\s*(<<|\w|::)/) + when "def" + valid = false if peek_match?(/^\s*(([+-\/*&\|^]|<<|>>|\|\||\&\&)=|\&\&|\|\|)/) + when "do" + valid = false if peek_match?(/^\s*([+-\/*]?=|\*|<|>|\&)/) + when *ENINDENT_CLAUSE + valid = false if peek_match?(/^\s*([+-\/*]?=|\*|<|>|\&|\|)/) + else + # no nothing + end if valid + + if valid + if token == "do" + if ![TkFOR, TkWHILE, TkUNTIL].include?(@indent_stack.last) + @indent += 1 + @indent_stack.push token_c + end + else + @indent += 1 + @indent_stack.push token_c + end + else + token_c = TkIDENTIFIER + end + + elsif DEINDENT_CLAUSE.include?(token) + @indent -= 1 + @indent_stack.pop + end + @lex_state = trans[0] + else + @lex_state = :EXPR_END + end + end + return Token(token_c, token) + end + end + + if @lex_state == :EXPR_FNAME + @lex_state = :EXPR_END + if peek(0) == '=' + token.concat getc + end + elsif @lex_state == :EXPR_BEG || @lex_state == :EXPR_DOT || + @lex_state == :EXPR_ARG + @lex_state = :EXPR_ARG + else + @lex_state = :EXPR_END + end + + if token[0, 1] =~ /[A-Z]/ + return Token(TkCONSTANT, token) + elsif token[token.size - 1, 1] =~ /[!?]/ + return Token(TkFID, token) + else + return Token(TkIDENTIFIER, token) + end + end + + def identify_here_document + ch = getc + # if lt = PERCENT_LTYPE[ch] + if ch == "-" + ch = getc + indent = true + end + if /['"`]/ =~ ch + user_quote = lt = ch + quoted = "" + while (c = getc) && c != lt + quoted.concat c + end + else + user_quote = nil + lt = '"' + quoted = ch.dup + while (c = getc) && c =~ /\w/ + quoted.concat c + end + ungetc + end + + ltback, @ltype = @ltype, lt + reserve = [] + while ch = getc + reserve.push ch + if ch == "\\" + reserve.push ch = getc + elsif ch == "\n" + break + end + end + + output_heredoc = reserve.join =~ /\A\r?\n\z/ + + if output_heredoc then + doc = '<<' + doc << '-' if indent + doc << "#{user_quote}#{quoted}#{user_quote}\n" + else + doc = '"' + end + + @here_header = false + while l = gets + l = l.sub(/(:?\r)?\n\z/, "\n") + if (indent ? l.strip : l.chomp) == quoted + break + end + doc << l + end + + if output_heredoc then + raise Error, "Missing terminating #{quoted} for string" unless l + + doc << l.chomp + else + doc << '"' + end + + @here_header = true + @here_readed.concat reserve + while ch = reserve.pop + ungetc ch + end + + token_class = output_heredoc ? RDoc::RubyLex::TkHEREDOC : Ltype2Token[lt] + @ltype = ltback + @lex_state = :EXPR_END + Token(token_class, doc) + end + + def identify_quotation + type = ch = getc + if lt = PERCENT_LTYPE[type] + ch = getc + elsif type =~ /\W/ + type = nil + lt = "\"" + else + return Token(TkMOD, '%') + end + # if ch !~ /\W/ + # ungetc + # next + # end + #@ltype = lt + @quoted = ch unless @quoted = PERCENT_PAREN[ch] + identify_string(lt, @quoted, type) + end + + def identify_number(op = "") + @lex_state = :EXPR_END + + num = op + + if peek(0) == "0" && peek(1) !~ /[.eE]/ + num << getc + + case peek(0) + when /[xX]/ + ch = getc + match = /[0-9a-fA-F_]/ + when /[bB]/ + ch = getc + match = /[01_]/ + when /[oO]/ + ch = getc + match = /[0-7_]/ + when /[dD]/ + ch = getc + match = /[0-9_]/ + when /[0-7]/ + match = /[0-7_]/ + when /[89]/ + raise Error, "Illegal octal digit" + else + return Token(TkINTEGER, num) + end + + num << ch if ch + + len0 = true + non_digit = false + while ch = getc + num << ch + if match =~ ch + if ch == "_" + if non_digit + raise Error, "trailing `#{ch}' in number" + else + non_digit = ch + end + else + non_digit = false + len0 = false + end + else + ungetc + num[-1, 1] = '' + if len0 + raise Error, "numeric literal without digits" + end + if non_digit + raise Error, "trailing `#{non_digit}' in number" + end + break + end + end + return Token(TkINTEGER, num) + end + + type = TkINTEGER + allow_point = true + allow_e = true + non_digit = false + while ch = getc + num << ch + case ch + when /[0-9]/ + non_digit = false + when "_" + non_digit = ch + when allow_point && "." + if non_digit + raise Error, "trailing `#{non_digit}' in number" + end + type = TkFLOAT + if peek(0) !~ /[0-9]/ + type = TkINTEGER + ungetc + num[-1, 1] = '' + break + end + allow_point = false + when allow_e && "e", allow_e && "E" + if non_digit + raise Error, "trailing `#{non_digit}' in number" + end + type = TkFLOAT + if peek(0) =~ /[+-]/ + num << getc + end + allow_e = false + allow_point = false + non_digit = ch + else + if non_digit + raise Error, "trailing `#{non_digit}' in number" + end + ungetc + num[-1, 1] = '' + break + end + end + + Token(type, num) + end + + def identify_string(ltype, quoted = ltype, type = nil) + close = PERCENT_PAREN.values.include?(quoted) + @ltype = ltype + @quoted = quoted + + str = if ltype == quoted and %w[" ' /].include? ltype then + ltype.dup + elsif RUBY_VERSION > '1.9' then + "%#{type or PERCENT_LTYPE.key ltype}#{PERCENT_PAREN_REV[quoted]||quoted}" + else + "%#{type or PERCENT_LTYPE.index ltype}#{PERCENT_PAREN_REV[quoted]||quoted}" + end + + subtype = nil + begin + nest = 0 + + while ch = getc + str << ch + + if @quoted == ch and nest <= 0 + break + elsif @ltype != "'" && @ltype != "]" && @ltype != ":" and ch == "#" + ch = getc + subtype = true + if ch == "{" then + str << ch << skip_inner_expression + next + else + ungetc + end + elsif ch == '\\' + if %w[' /].include? @ltype then + case ch = getc + when "\\", "\n", "'" + when @ltype + str << ch + else + ungetc + end + else + str << read_escape + end + end + + if close then + if PERCENT_PAREN[ch] == @quoted + nest += 1 + elsif ch == @quoted + nest -= 1 + end + end + end + + if @ltype == "/" + while peek(0) =~ /i|m|x|o|e|s|u|n/ + str << getc + end + end + + if subtype + Token(DLtype2Token[ltype], str) + else + Token(Ltype2Token[ltype], str) + end + ensure + @ltype = nil + @quoted = nil + @lex_state = :EXPR_END + end + end + + def skip_inner_expression + res = "" + nest = 0 + while ch = getc + res << ch + if ch == '}' + break if nest.zero? + nest -= 1 + elsif ch == '{' + nest += 1 + end + end + res + end + + def identify_comment + @ltype = "#" + + comment = '#' + + while ch = getc + # if ch == "\\" #" + # read_escape + # end + if ch == "\n" + @ltype = nil + ungetc + break + end + + comment << ch + end + + return Token(TkCOMMENT, comment) + end + + def read_escape + escape = '' + ch = getc + + case ch + when "\n", "\r", "\f" + escape << ch + when "\\", "n", "t", "r", "f", "v", "a", "e", "b", "s" #" + escape << ch + when /[0-7]/ + ungetc ch + 3.times do + ch = getc + case ch + when /[0-7]/ + escape << ch + when nil + break + else + ungetc + break + end + end + + when "x" + escape << ch + + 2.times do + ch = getc + case ch + when /[0-9a-fA-F]/ + escape << ch + when nil + break + else + ungetc + break + end + end + + when "M" + escape << ch + + ch = getc + if ch != '-' + ungetc + else + escape << ch + + ch = getc + if ch == "\\" #" + ungetc + escape << read_escape + else + escape << ch + end + end + + when "C", "c" #, "^" + escape << ch + + if ch == "C" + ch = getc + + if ch == "-" + escape << ch + ch = getc + escape << ch + + escape << read_escape if ch == "\\" + else + ungetc + end + elsif (ch = getc) == "\\" #" + escape << ch << read_escape + end + else + escape << ch + + # other characters + end + + escape + end + + # :startdoc: + +end + +#RDoc::RubyLex.debug_level = 1 + diff --git a/jni/ruby/lib/rdoc/ruby_token.rb b/jni/ruby/lib/rdoc/ruby_token.rb new file mode 100644 index 0000000..f091e1a --- /dev/null +++ b/jni/ruby/lib/rdoc/ruby_token.rb @@ -0,0 +1,460 @@ +#-- +# irb/ruby-token.rb - ruby tokens +# $Release Version: 0.9.5$ +# $Revision: 11708 $ +# $Date: 2007-02-12 15:01:19 -0800 (Mon, 12 Feb 2007) $ +# by Keiju ISHITSUKA(keiju@ruby-lang.org) +#++ +# Definitions of all tokens involved in the lexical analysis. +# +# This class is not documented because it is so deep in the internals. + +module RDoc::RubyToken + # :stopdoc: + + EXPR_BEG = :EXPR_BEG + EXPR_MID = :EXPR_MID + EXPR_END = :EXPR_END + EXPR_ARG = :EXPR_ARG + EXPR_FNAME = :EXPR_FNAME + EXPR_DOT = :EXPR_DOT + EXPR_CLASS = :EXPR_CLASS + + # for ruby 1.4X + if !defined?(Symbol) + Symbol = Integer + end + + def set_token_position(line, char) + @prev_line_no = line + @prev_char_no = char + end + + class Token + def initialize(seek, line_no, char_no, text = nil) + @seek = seek + @line_no = line_no + @char_no = char_no + @text = text + end + + attr_reader :seek + attr_reader :line_no + attr_reader :char_no + + attr_accessor :text + + def ==(other) + self.class == other.class and + other.line_no == @line_no and + other.char_no == @char_no and + other.text == @text + end + + ## + # Because we're used in contexts that expect to return a token, we set the + # text string and then return ourselves + + def set_text(text) + @text = text + self + end + + def inspect # :nodoc: + klass = self.class.name.split('::').last + "{%s %d, %d:%d %p}" % [klass, @seek, @line_no, @char_no, @text] + end + + end + + class TkNode < Token + def initialize(seek, line_no, char_no, node = nil) + super seek, line_no, char_no + @node = node + end + + attr_reader:node + + def ==(other) + self.class == other.class and + other.line_no == @line_no and + other.char_no == @char_no and + other.node == @node + end + + def set_text text + @node = text + self + end + + alias text node + + def inspect # :nodoc: + klass = self.class.name.split('::').last + "{%s %d, %d:%d %p}" % [klass, @seek, @line_no, @char_no, @node] + end + + end + + class TkId < Token + def initialize(seek, line_no, char_no, name) + super(seek, line_no, char_no) + @name = name + end + attr_reader:name + + def ==(other) + self.class == other.class and + other.line_no == @line_no and + other.char_no == @char_no and + other.name == @name + end + + def set_text text + @name = text + self + end + + alias text name + + def inspect # :nodoc: + klass = self.class.name.split('::').last + "{%s %d, %d:%d %p}" % [klass, @seek, @line_no, @char_no, @name] + end + + end + + class TkKW < TkId + end + + class TkVal < Token + def initialize(seek, line_no, char_no, value = nil) + super(seek, line_no, char_no) + @value = value + end + attr_accessor :value + + def ==(other) + self.class == other.class and + other.line_no == @line_no and + other.char_no == @char_no and + other.value == @value + end + + def set_text text + @value = text + self + end + + alias text value + + def inspect # :nodoc: + klass = self.class.name.split('::').last + "{%s %s, %d:%d %p}" % [klass, @seek, @line_no, @char_no, @value] + end + + end + + class TkOp < Token + def initialize(seek, line_no, char_no, name = nil) + super seek, line_no, char_no + @name = name + end + + attr_accessor :name + + def ==(other) + self.class == other.class and + other.line_no == @line_no and + other.char_no == @char_no and + other.name == @name + end + + def set_text text + @name = text + self + end + + alias text name + + def inspect # :nodoc: + klass = self.class.name.split('::').last + "{%s %d, %d:%d %p}" % [klass, @seek, @line_no, @char_no, @name] + end + + end + + class TkOPASGN < TkOp + def initialize(seek, line_no, char_no, op) + super(seek, line_no, char_no) + op = TkReading2Token[op][0] unless op.kind_of?(Symbol) + @op = op + @text = nil + end + + attr_reader:op + + def ==(other) + self.class == other.class and + other.line_no == @line_no and + other.char_no == @char_no and + other.op == @op + end + + def text + @text ||= "#{TkToken2Reading[op]}=" + end + + def inspect # :nodoc: + klass = self.class.name.split('::').last + "{%s %d, %d:%d %p}" % [klass, @seek, @line_no, @char_no, @op] + end + + end + + class TkUnknownChar < Token + def initialize(seek, line_no, char_no, name) + super(seek, line_no, char_no) + @name = name + end + attr_reader:name + + def ==(other) + self.class == other.class and + other.line_no == @line_no and + other.char_no == @char_no and + other.name == @name + end + + def set_text text + @name = text + self + end + + alias text name + + def inspect # :nodoc: + klass = self.class.name.split('::').last + "{%s %d, %d:%d %p}" % [klass, @seek, @line_no, @char_no, @name] + end + + end + + class TkError < Token + end + + def Token(token, value = nil) + value ||= TkToken2Reading[token] + + case token + when String + if (tk = TkReading2Token[token]).nil? + IRB.fail TkReading2TokenNoKey, token + end + + tk = Token(tk[0], value) + + if tk.kind_of?(TkOp) then + tk.name = token + end + when Symbol + if (tk = TkSymbol2Token[token]).nil? + IRB.fail TkSymbol2TokenNoKey, token + end + + tk = Token(tk[0], value) + else + if token.instance_method(:initialize).arity == 3 then + tk = token.new(@prev_seek, @prev_line_no, @prev_char_no) + tk.set_text value + else + tk = token.new(@prev_seek, @prev_line_no, @prev_char_no, value) + end + end + + tk + end + + TokenDefinitions = [ + [:TkCLASS, TkKW, "class", :EXPR_CLASS], + [:TkMODULE, TkKW, "module", :EXPR_BEG], + [:TkDEF, TkKW, "def", :EXPR_FNAME], + [:TkUNDEF, TkKW, "undef", :EXPR_FNAME], + [:TkBEGIN, TkKW, "begin", :EXPR_BEG], + [:TkRESCUE, TkKW, "rescue", :EXPR_MID], + [:TkENSURE, TkKW, "ensure", :EXPR_BEG], + [:TkEND, TkKW, "end", :EXPR_END], + [:TkIF, TkKW, "if", :EXPR_BEG, :TkIF_MOD], + [:TkUNLESS, TkKW, "unless", :EXPR_BEG, :TkUNLESS_MOD], + [:TkTHEN, TkKW, "then", :EXPR_BEG], + [:TkELSIF, TkKW, "elsif", :EXPR_BEG], + [:TkELSE, TkKW, "else", :EXPR_BEG], + [:TkCASE, TkKW, "case", :EXPR_BEG], + [:TkWHEN, TkKW, "when", :EXPR_BEG], + [:TkWHILE, TkKW, "while", :EXPR_BEG, :TkWHILE_MOD], + [:TkUNTIL, TkKW, "until", :EXPR_BEG, :TkUNTIL_MOD], + [:TkFOR, TkKW, "for", :EXPR_BEG], + [:TkBREAK, TkKW, "break", :EXPR_MID], + [:TkNEXT, TkKW, "next", :EXPR_END], + [:TkREDO, TkKW, "redo", :EXPR_END], + [:TkRETRY, TkKW, "retry", :EXPR_END], + [:TkIN, TkKW, "in", :EXPR_BEG], + [:TkDO, TkKW, "do", :EXPR_BEG], + [:TkRETURN, TkKW, "return", :EXPR_MID], + [:TkYIELD, TkKW, "yield", :EXPR_END], + [:TkSUPER, TkKW, "super", :EXPR_END], + [:TkSELF, TkKW, "self", :EXPR_END], + [:TkNIL, TkKW, "nil", :EXPR_END], + [:TkTRUE, TkKW, "true", :EXPR_END], + [:TkFALSE, TkKW, "false", :EXPR_END], + [:TkAND, TkKW, "and", :EXPR_BEG], + [:TkOR, TkKW, "or", :EXPR_BEG], + [:TkNOT, TkKW, "not", :EXPR_BEG], + [:TkIF_MOD, TkKW], + [:TkUNLESS_MOD, TkKW], + [:TkWHILE_MOD, TkKW], + [:TkUNTIL_MOD, TkKW], + [:TkALIAS, TkKW, "alias", :EXPR_FNAME], + [:TkDEFINED, TkKW, "defined?", :EXPR_END], + [:TklBEGIN, TkKW, "BEGIN", :EXPR_END], + [:TklEND, TkKW, "END", :EXPR_END], + [:Tk__LINE__, TkKW, "__LINE__", :EXPR_END], + [:Tk__FILE__, TkKW, "__FILE__", :EXPR_END], + + [:TkIDENTIFIER, TkId], + [:TkFID, TkId], + [:TkGVAR, TkId], + [:TkCVAR, TkId], + [:TkIVAR, TkId], + [:TkCONSTANT, TkId], + + [:TkINTEGER, TkVal], + [:TkFLOAT, TkVal], + [:TkSTRING, TkVal], + [:TkHEREDOC, TkVal], + [:TkXSTRING, TkVal], + [:TkREGEXP, TkVal], + [:TkSYMBOL, TkVal], + [:TkCHAR, TkVal], + + [:TkDSTRING, TkNode], + [:TkDXSTRING, TkNode], + [:TkDREGEXP, TkNode], + [:TkNTH_REF, TkNode], + [:TkBACK_REF, TkNode], + + [:TkUPLUS, TkOp, "+@"], + [:TkUMINUS, TkOp, "-@"], + [:TkPOW, TkOp, "**"], + [:TkCMP, TkOp, "<=>"], + [:TkEQ, TkOp, "=="], + [:TkEQQ, TkOp, "==="], + [:TkNEQ, TkOp, "!="], + [:TkGEQ, TkOp, ">="], + [:TkLEQ, TkOp, "<="], + [:TkANDOP, TkOp, "&&"], + [:TkOROP, TkOp, "||"], + [:TkMATCH, TkOp, "=~"], + [:TkNMATCH, TkOp, "!~"], + [:TkDOT2, TkOp, ".."], + [:TkDOT3, TkOp, "..."], + [:TkAREF, TkOp, "[]"], + [:TkASET, TkOp, "[]="], + [:TkLSHFT, TkOp, "<<"], + [:TkRSHFT, TkOp, ">>"], + [:TkCOLON2, TkOp, '::'], + [:TkCOLON3, TkOp, '::'], + #[:OPASGN, TkOp], # +=, -= etc. # + [:TkASSOC, TkOp, "=>"], + [:TkQUESTION, TkOp, "?"], #? + [:TkCOLON, TkOp, ":"], #: + + [:TkfLPAREN, Token, "("], # func( # + [:TkfLBRACK, Token, "["], # func[ # + [:TkfLBRACE, Token, "{"], # func{ # + [:TkSYMBEG, Token, ":"], # :SYMBOL + + [:TkAMPER, TkOp, "&"], + [:TkGT, TkOp, ">"], + [:TkLT, TkOp, "<"], + [:TkPLUS, TkOp, "+"], + [:TkSTAR, TkOp, "*"], + [:TkMINUS, TkOp, "-"], + [:TkMULT, TkOp, "*"], + [:TkDIV, TkOp, "/"], + [:TkMOD, TkOp, "%"], + [:TkBITOR, TkOp, "|"], + [:TkBITXOR, TkOp, "^"], + [:TkBITAND, TkOp, "&"], + [:TkBITNOT, TkOp, "~"], + [:TkNOTOP, TkOp, "!"], + + [:TkBACKQUOTE, TkOp, "`"], + + [:TkASSIGN, Token, "="], + [:TkDOT, Token, "."], + [:TkLPAREN, Token, "("], #(exp) + [:TkLBRACK, Token, "["], #[arry] + [:TkLBRACE, Token, "{"], #{hash} + [:TkRPAREN, Token, ")"], + [:TkRBRACK, Token, "]"], + [:TkRBRACE, Token, "}"], + [:TkCOMMA, Token, ","], + [:TkSEMICOLON, Token, ";"], + + [:TkCOMMENT, TkVal], + [:TkSPACE, Token, " "], + [:TkNL, Token, "\n"], + [:TkEND_OF_SCRIPT], + + [:TkBACKSLASH, TkUnknownChar, "\\"], + [:TkAT, TkUnknownChar, "@"], + [:TkDOLLAR, TkUnknownChar, "$"], + ] + + # {reading => token_class} + # {reading => [token_class, *opt]} + TkReading2Token = {} + TkToken2Reading = {} + TkSymbol2Token = {} + + def self.def_token(token_n, super_token = Token, reading = nil, *opts) + token_n = token_n.id2name if token_n.kind_of?(Symbol) + if const_defined?(token_n) + IRB.fail AlreadyDefinedToken, token_n + end + token_c = eval("class #{token_n} < #{super_token}; end; #{token_n}") + + if reading + TkToken2Reading[token_c] = reading + + return if TkReading2Token[reading] + + if opts.empty? + TkReading2Token[reading] = [token_c] + else + TkReading2Token[reading] = [token_c].concat(opts) + end + end + TkSymbol2Token[token_n.intern] = token_c + end + + for defs in TokenDefinitions + def_token(*defs) + end + + def_token :TkRD_COMMENT, TkCOMMENT + + NEWLINE_TOKEN = TkNL.new 0, 0, 0, "\n" + + class TkSYMBOL + + def to_sym + @sym ||= text[1..-1].intern + end + + end + + # :startdoc: +end + diff --git a/jni/ruby/lib/rdoc/rubygems_hook.rb b/jni/ruby/lib/rdoc/rubygems_hook.rb new file mode 100644 index 0000000..c4eaddb --- /dev/null +++ b/jni/ruby/lib/rdoc/rubygems_hook.rb @@ -0,0 +1,253 @@ +require 'rubygems' +require 'rubygems/user_interaction' +require 'fileutils' +require 'rdoc' + +## +# Gem::RDoc provides methods to generate RDoc and ri data for installed gems +# upon gem installation. +# +# This file is automatically required by RubyGems 1.9 and newer. + +class RDoc::RubygemsHook + + include Gem::UserInteraction + extend Gem::UserInteraction + + @rdoc_version = nil + @specs = [] + + ## + # Force installation of documentation? + + attr_accessor :force + + ## + # Generate rdoc? + + attr_accessor :generate_rdoc + + ## + # Generate ri data? + + attr_accessor :generate_ri + + class << self + + ## + # Loaded version of RDoc. Set by ::load_rdoc + + attr_reader :rdoc_version + + end + + ## + # Post installs hook that generates documentation for each specification in + # +specs+ + + def self.generation_hook installer, specs + start = Time.now + types = installer.document + + generate_rdoc = types.include? 'rdoc' + generate_ri = types.include? 'ri' + + specs.each do |spec| + new(spec, generate_rdoc, generate_ri).generate + end + + return unless generate_rdoc or generate_ri + + duration = (Time.now - start).to_i + names = specs.map(&:name).join ', ' + + say "Done installing documentation for #{names} after #{duration} seconds" + end + + ## + # Loads the RDoc generator + + def self.load_rdoc + return if @rdoc_version + + require 'rdoc/rdoc' + + @rdoc_version = Gem::Version.new ::RDoc::VERSION + end + + ## + # Creates a new documentation generator for +spec+. RDoc and ri data + # generation can be enabled or disabled through +generate_rdoc+ and + # +generate_ri+ respectively. + # + # Only +generate_ri+ is enabled by default. + + def initialize spec, generate_rdoc = false, generate_ri = true + @doc_dir = spec.doc_dir + @force = false + @rdoc = nil + @spec = spec + + @generate_rdoc = generate_rdoc + @generate_ri = generate_ri + + @rdoc_dir = spec.doc_dir 'rdoc' + @ri_dir = spec.doc_dir 'ri' + end + + ## + # Removes legacy rdoc arguments from +args+ + #-- + # TODO move to RDoc::Options + + def delete_legacy_args args + args.delete '--inline-source' + args.delete '--promiscuous' + args.delete '-p' + args.delete '--one-file' + end + + ## + # Generates documentation using the named +generator+ ("darkfish" or "ri") + # and following the given +options+. + # + # Documentation will be generated into +destination+ + + def document generator, options, destination + generator_name = generator + + options = options.dup + options.exclude ||= [] # TODO maybe move to RDoc::Options#finish + options.setup_generator generator + options.op_dir = destination + options.finish + + generator = options.generator.new @rdoc.store, options + + @rdoc.options = options + @rdoc.generator = generator + + say "Installing #{generator_name} documentation for #{@spec.full_name}" + + FileUtils.mkdir_p options.op_dir + + Dir.chdir options.op_dir do + begin + @rdoc.class.current = @rdoc + @rdoc.generator.generate + ensure + @rdoc.class.current = nil + end + end + end + + ## + # Generates RDoc and ri data + + def generate + return if @spec.default_gem? + return unless @generate_ri or @generate_rdoc + + setup + + options = nil + + args = @spec.rdoc_options + + if @spec.respond_to? :source_paths then + args.concat @spec.source_paths + else + args.concat @spec.require_paths + end + + args.concat @spec.extra_rdoc_files + + case config_args = Gem.configuration[:rdoc] + when String then + args = args.concat config_args.split + when Array then + args = args.concat config_args + end + + delete_legacy_args args + + Dir.chdir @spec.full_gem_path do + options = ::RDoc::Options.new + options.default_title = "#{@spec.full_name} Documentation" + options.parse args + end + + options.quiet = !Gem.configuration.really_verbose + + @rdoc = new_rdoc + @rdoc.options = options + + store = RDoc::Store.new + store.encoding = options.encoding if options.respond_to? :encoding + store.dry_run = options.dry_run + store.main = options.main_page + store.title = options.title + + @rdoc.store = store + + say "Parsing documentation for #{@spec.full_name}" + + Dir.chdir @spec.full_gem_path do + @rdoc.parse_files options.files + end + + document 'ri', options, @ri_dir if + @generate_ri and (@force or not File.exist? @ri_dir) + + document 'darkfish', options, @rdoc_dir if + @generate_rdoc and (@force or not File.exist? @rdoc_dir) + end + + ## + # #new_rdoc creates a new RDoc instance. This method is provided only to + # make testing easier. + + def new_rdoc # :nodoc: + ::RDoc::RDoc.new + end + + ## + # Is rdoc documentation installed? + + def rdoc_installed? + File.exist? @rdoc_dir + end + + ## + # Removes generated RDoc and ri data + + def remove + base_dir = @spec.base_dir + + raise Gem::FilePermissionError, base_dir unless File.writable? base_dir + + FileUtils.rm_rf @rdoc_dir + FileUtils.rm_rf @ri_dir + end + + ## + # Is ri data installed? + + def ri_installed? + File.exist? @ri_dir + end + + ## + # Prepares the spec for documentation generation + + def setup + self.class.load_rdoc + + raise Gem::FilePermissionError, @doc_dir if + File.exist?(@doc_dir) and not File.writable?(@doc_dir) + + FileUtils.mkdir_p @doc_dir unless File.exist? @doc_dir + end + +end + diff --git a/jni/ruby/lib/rdoc/servlet.rb b/jni/ruby/lib/rdoc/servlet.rb new file mode 100644 index 0000000..ec8fd73 --- /dev/null +++ b/jni/ruby/lib/rdoc/servlet.rb @@ -0,0 +1,441 @@ +require 'rdoc' +require 'time' +require 'webrick' + +## +# This is a WEBrick servlet that allows you to browse ri documentation. +# +# You can show documentation through either `ri --server` or, with RubyGems +# 2.0 or newer, `gem server`. For ri, the server runs on port 8214 by +# default. For RubyGems the server runs on port 8808 by default. +# +# You can use this servlet in your own project by mounting it on a WEBrick +# server: +# +# require 'webrick' +# +# server = WEBrick::HTTPServer.new Port: 8000 +# +# server.mount '/', RDoc::Servlet +# +# If you want to mount the servlet some other place than the root, provide the +# base path when mounting: +# +# server.mount '/rdoc', RDoc::Servlet, '/rdoc' + +class RDoc::Servlet < WEBrick::HTTPServlet::AbstractServlet + + @server_stores = Hash.new { |hash, server| hash[server] = {} } + @cache = Hash.new { |hash, store| hash[store] = {} } + + ## + # Maps an asset type to its path on the filesystem + + attr_reader :asset_dirs + + ## + # An RDoc::Options instance used for rendering options + + attr_reader :options + + ## + # Creates an instance of this servlet that shares cached data between + # requests. + + def self.get_instance server, *options # :nodoc: + stores = @server_stores[server] + + new server, stores, @cache, *options + end + + ## + # Creates a new WEBrick servlet. + # + # Use +mount_path+ when mounting the servlet somewhere other than /. + # + # Use +extra_doc_dirs+ for additional documentation directories. + # + # +server+ is provided automatically by WEBrick when mounting. +stores+ and + # +cache+ are provided automatically by the servlet. + + def initialize server, stores, cache, mount_path = nil, extra_doc_dirs = [] + super server + + @cache = cache + @mount_path = mount_path + @extra_doc_dirs = extra_doc_dirs + @stores = stores + + @options = RDoc::Options.new + @options.op_dir = '.' + + darkfish_dir = nil + + # HACK dup + $LOAD_PATH.each do |path| + darkfish_dir = File.join path, 'rdoc/generator/template/darkfish/' + next unless File.directory? darkfish_dir + @options.template_dir = darkfish_dir + break + end + + @asset_dirs = { + :darkfish => darkfish_dir, + :json_index => + File.expand_path('../generator/template/json_index/', __FILE__), + } + end + + ## + # Serves the asset at the path in +req+ for +generator_name+ via +res+. + + def asset generator_name, req, res + asset_dir = @asset_dirs[generator_name] + + asset_path = File.join asset_dir, req.path + + if_modified_since req, res, asset_path + + res.body = File.read asset_path + + res.content_type = case req.path + when /css$/ then 'text/css' + when /js$/ then 'application/javascript' + else 'application/octet-stream' + end + end + + ## + # GET request entry point. Fills in +res+ for the path, etc. in +req+. + + def do_GET req, res + req.path.sub!(/^#{Regexp.escape @mount_path}/o, '') if @mount_path + + case req.path + when '/' then + root req, res + when '/rdoc.css', '/js/darkfish.js', '/js/jquery.js', '/js/search.js', + %r%^/images/% then + asset :darkfish, req, res + when '/js/navigation.js', '/js/searcher.js' then + asset :json_index, req, res + when '/js/search_index.js' then + root_search req, res + else + show_documentation req, res + end + rescue WEBrick::HTTPStatus::NotFound => e + generator = generator_for RDoc::Store.new + + not_found generator, req, res, e.message + rescue WEBrick::HTTPStatus::Status + raise + rescue => e + error e, req, res + end + + ## + # Fills in +res+ with the class, module or page for +req+ from +store+. + # + # +path+ is relative to the mount_path and is used to determine the class, + # module or page name (/RDoc/Servlet.html becomes RDoc::Servlet). + # +generator+ is used to create the page. + + def documentation_page store, generator, path, req, res + name = path.sub(/.html$/, '').gsub '/', '::' + + if klass = store.find_class_or_module(name) then + res.body = generator.generate_class klass + elsif page = store.find_text_page(name.sub(/_([^_]*)$/, '.\1')) then + res.body = generator.generate_page page + else + not_found generator, req, res + end + end + + ## + # Creates the JSON search index on +res+ for the given +store+. +generator+ + # must respond to \#json_index to build. +req+ is ignored. + + def documentation_search store, generator, req, res + json_index = @cache[store].fetch :json_index do + @cache[store][:json_index] = + JSON.dump generator.json_index.build_index + end + + res.content_type = 'application/javascript' + res.body = "var search_data = #{json_index}" + end + + ## + # Returns the RDoc::Store and path relative to +mount_path+ for + # documentation at +path+. + + def documentation_source path + _, source_name, path = path.split '/', 3 + + store = @stores[source_name] + return store, path if store + + store = store_for source_name + + store.load_all + + @stores[source_name] = store + + return store, path + end + + ## + # Generates an error page for the +exception+ while handling +req+ on +res+. + + def error exception, req, res + backtrace = exception.backtrace.join "\n" + + res.content_type = 'text/html' + res.status = 500 + res.body = <<-BODY +<!DOCTYPE html> +<html> +<head> +<meta content="text/html; charset=UTF-8" http-equiv="Content-Type"> + +<title>Error - #{ERB::Util.html_escape exception.class}</title> + +<link type="text/css" media="screen" href="#{@mount_path}/rdoc.css" rel="stylesheet"> +</head> +<body> +<h1>Error</h1> + +<p>While processing <code>#{ERB::Util.html_escape req.request_uri}</code> the +RDoc (#{ERB::Util.html_escape RDoc::VERSION}) server has encountered a +<code>#{ERB::Util.html_escape exception.class}</code> +exception: + +<pre>#{ERB::Util.html_escape exception.message}</pre> + +<p>Please report this to the +<a href="https://github.com/rdoc/rdoc/issues">RDoc issues tracker</a>. Please +include the RDoc version, the URI above and exception class, message and +backtrace. If you're viewing a gem's documentation, include the gem name and +version. If you're viewing Ruby's documentation, include the version of ruby. + +<p>Backtrace: + +<pre>#{ERB::Util.html_escape backtrace}</pre> + +</body> +</html> + BODY + end + + ## + # Instantiates a Darkfish generator for +store+ + + def generator_for store + generator = RDoc::Generator::Darkfish.new store, @options + generator.file_output = false + generator.asset_rel_path = '..' + + rdoc = RDoc::RDoc.new + rdoc.store = store + rdoc.generator = generator + rdoc.options = @options + + @options.main_page = store.main + @options.title = store.title + + generator + end + + ## + # Handles the If-Modified-Since HTTP header on +req+ for +path+. If the + # file has not been modified a Not Modified response is returned. If the + # file has been modified a Last-Modified header is added to +res+. + + def if_modified_since req, res, path = nil + last_modified = File.stat(path).mtime if path + + res['last-modified'] = last_modified.httpdate + + return unless ims = req['if-modified-since'] + + ims = Time.parse ims + + unless ims < last_modified then + res.body = '' + raise WEBrick::HTTPStatus::NotModified + end + end + + ## + # Returns an Array of installed documentation. + # + # Each entry contains the documentation name (gem name, 'Ruby + # Documentation', etc.), the path relative to the mount point, whether the + # documentation exists, the type of documentation (See RDoc::RI::Paths#each) + # and the filesystem to the RDoc::Store for the documentation. + + def installed_docs + extra_counter = 0 + ri_paths.map do |path, type| + store = RDoc::Store.new path, type + exists = File.exist? store.cache_path + + case type + when :gem then + gem_path = path[%r%/([^/]*)/ri$%, 1] + [gem_path, "#{gem_path}/", exists, type, path] + when :system then + ['Ruby Documentation', 'ruby/', exists, type, path] + when :site then + ['Site Documentation', 'site/', exists, type, path] + when :home then + ['Home Documentation', 'home/', exists, type, path] + when :extra then + extra_counter += 1 + store.load_cache if exists + title = store.title || "Extra Documentation" + [title, "extra-#{extra_counter}/", exists, type, path] + end + end + end + + ## + # Returns a 404 page built by +generator+ for +req+ on +res+. + + def not_found generator, req, res, message = nil + message ||= "The page <kbd>#{ERB::Util.h req.path}</kbd> was not found" + res.body = generator.generate_servlet_not_found message + res.status = 404 + end + + ## + # Enumerates the ri paths. See RDoc::RI::Paths#each + + def ri_paths &block + RDoc::RI::Paths.each true, true, true, :all, *@extra_doc_dirs, &block #TODO: pass extra_dirs + end + + ## + # Generates the root page on +res+. +req+ is ignored. + + def root req, res + generator = RDoc::Generator::Darkfish.new nil, @options + + res.body = generator.generate_servlet_root installed_docs + + res.content_type = 'text/html' + end + + ## + # Generates a search index for the root page on +res+. +req+ is ignored. + + def root_search req, res + search_index = [] + info = [] + + installed_docs.map do |name, href, exists, type, path| + next unless exists + + search_index << name + + case type + when :gem + gemspec = path.gsub(%r%/doc/([^/]*?)/ri$%, + '/specifications/\1.gemspec') + + spec = Gem::Specification.load gemspec + + path = spec.full_name + comment = spec.summary + when :system then + path = 'ruby' + comment = 'Documentation for the Ruby standard library' + when :site then + path = 'site' + comment = 'Documentation for non-gem libraries' + when :home then + path = 'home' + comment = 'Documentation from your home directory' + when :extra + comment = name + end + + info << [name, '', path, '', comment] + end + + index = { + :index => { + :searchIndex => search_index, + :longSearchIndex => search_index, + :info => info, + } + } + + res.body = "var search_data = #{JSON.dump index};" + res.content_type = 'application/javascript' + end + + ## + # Displays documentation for +req+ on +res+, whether that be HTML or some + # asset. + + def show_documentation req, res + store, path = documentation_source req.path + + if_modified_since req, res, store.cache_path + + generator = generator_for store + + case path + when nil, '', 'index.html' then + res.body = generator.generate_index + when 'table_of_contents.html' then + res.body = generator.generate_table_of_contents + when 'js/search_index.js' then + documentation_search store, generator, req, res + else + documentation_page store, generator, path, req, res + end + ensure + res.content_type ||= 'text/html' + end + + ## + # Returns an RDoc::Store for the given +source_name+ ('ruby' or a gem name). + + def store_for source_name + case source_name + when 'home' then + RDoc::Store.new RDoc::RI::Paths.home_dir, :home + when 'ruby' then + RDoc::Store.new RDoc::RI::Paths.system_dir, :system + when 'site' then + RDoc::Store.new RDoc::RI::Paths.site_dir, :site + when /^extra-(\d+)$/ then + index = $1.to_i - 1 + ri_dir = installed_docs[index][4] + RDoc::Store.new ri_dir, :extra + else + ri_dir, type = ri_paths.find do |dir, dir_type| + next unless dir_type == :gem + + source_name == dir[%r%/([^/]*)/ri$%, 1] + end + + raise WEBrick::HTTPStatus::NotFound, + "Could not find gem \"#{source_name}\". Are you sure you installed it?" unless ri_dir + + store = RDoc::Store.new ri_dir, type + + return store if File.exist? store.cache_path + + raise WEBrick::HTTPStatus::NotFound, + "Could not find documentation for \"#{source_name}\". Please run `gem rdoc --ri gem_name`" + + end + end + +end + diff --git a/jni/ruby/lib/rdoc/single_class.rb b/jni/ruby/lib/rdoc/single_class.rb new file mode 100644 index 0000000..358e1f3 --- /dev/null +++ b/jni/ruby/lib/rdoc/single_class.rb @@ -0,0 +1,25 @@ +## +# A singleton class + +class RDoc::SingleClass < RDoc::ClassModule + + ## + # Adds the superclass to the included modules. + + def ancestors + superclass ? super + [superclass] : super + end + + def aref_prefix # :nodoc: + 'sclass' + end + + ## + # The definition of this singleton class, <tt>class << MyClassName</tt> + + def definition + "class << #{full_name}" + end + +end + diff --git a/jni/ruby/lib/rdoc/stats.rb b/jni/ruby/lib/rdoc/stats.rb new file mode 100644 index 0000000..94fdd27 --- /dev/null +++ b/jni/ruby/lib/rdoc/stats.rb @@ -0,0 +1,461 @@ +## +# RDoc statistics collector which prints a summary and report of a project's +# documentation totals. + +class RDoc::Stats + + include RDoc::Text + + ## + # Output level for the coverage report + + attr_reader :coverage_level + + ## + # Count of files parsed during parsing + + attr_reader :files_so_far + + ## + # Total number of files found + + attr_reader :num_files + + ## + # Creates a new Stats that will have +num_files+. +verbosity+ defaults to 1 + # which will create an RDoc::Stats::Normal outputter. + + def initialize store, num_files, verbosity = 1 + @num_files = num_files + @store = store + + @coverage_level = 0 + @doc_items = nil + @files_so_far = 0 + @fully_documented = false + @num_params = 0 + @percent_doc = nil + @start = Time.now + @undoc_params = 0 + + @display = case verbosity + when 0 then Quiet.new num_files + when 1 then Normal.new num_files + else Verbose.new num_files + end + end + + ## + # Records the parsing of an alias +as+. + + def add_alias as + @display.print_alias as + end + + ## + # Records the parsing of an attribute +attribute+ + + def add_attribute attribute + @display.print_attribute attribute + end + + ## + # Records the parsing of a class +klass+ + + def add_class klass + @display.print_class klass + end + + ## + # Records the parsing of +constant+ + + def add_constant constant + @display.print_constant constant + end + + ## + # Records the parsing of +file+ + + def add_file(file) + @files_so_far += 1 + @display.print_file @files_so_far, file + end + + ## + # Records the parsing of +method+ + + def add_method(method) + @display.print_method method + end + + ## + # Records the parsing of a module +mod+ + + def add_module(mod) + @display.print_module mod + end + + ## + # Call this to mark the beginning of parsing for display purposes + + def begin_adding + @display.begin_adding + end + + ## + # Calculates documentation totals and percentages for classes, modules, + # constants, attributes and methods. + + def calculate + return if @doc_items + + ucm = @store.unique_classes_and_modules + + classes = @store.unique_classes.reject { |cm| cm.full_name == 'Object' } + + constants = [] + ucm.each { |cm| constants.concat cm.constants } + + methods = [] + ucm.each { |cm| methods.concat cm.method_list } + + attributes = [] + ucm.each { |cm| attributes.concat cm.attributes } + + @num_attributes, @undoc_attributes = doc_stats attributes + @num_classes, @undoc_classes = doc_stats classes + @num_constants, @undoc_constants = doc_stats constants + @num_methods, @undoc_methods = doc_stats methods + @num_modules, @undoc_modules = doc_stats @store.unique_modules + + @num_items = + @num_attributes + + @num_classes + + @num_constants + + @num_methods + + @num_modules + + @num_params + + @undoc_items = + @undoc_attributes + + @undoc_classes + + @undoc_constants + + @undoc_methods + + @undoc_modules + + @undoc_params + + @doc_items = @num_items - @undoc_items + end + + ## + # Sets coverage report level. Accepted values are: + # + # false or nil:: No report + # 0:: Classes, modules, constants, attributes, methods + # 1:: Level 0 + method parameters + + def coverage_level= level + level = -1 unless level + + @coverage_level = level + end + + ## + # Returns the length and number of undocumented items in +collection+. + + def doc_stats collection + visible = collection.select { |item| item.display? } + [visible.length, visible.count { |item| not item.documented? }] + end + + ## + # Call this to mark the end of parsing for display purposes + + def done_adding + @display.done_adding + end + + ## + # The documentation status of this project. +true+ when 100%, +false+ when + # less than 100% and +nil+ when unknown. + # + # Set by calling #calculate + + def fully_documented? + @fully_documented + end + + ## + # A report that says you did a great job! + + def great_job + report = RDoc::Markup::Document.new + + report << RDoc::Markup::Paragraph.new('100% documentation!') + report << RDoc::Markup::Paragraph.new('Great Job!') + + report + end + + ## + # Calculates the percentage of items documented. + + def percent_doc + return @percent_doc if @percent_doc + + @fully_documented = (@num_items - @doc_items) == 0 + + @percent_doc = @doc_items.to_f / @num_items * 100 if @num_items.nonzero? + @percent_doc ||= 0 + + @percent_doc + end + + ## + # Returns a report on which items are not documented + + def report + if @coverage_level > 0 then + extend RDoc::Text + end + + if @coverage_level.zero? then + calculate + + return great_job if @num_items == @doc_items + end + + ucm = @store.unique_classes_and_modules + + report = RDoc::Markup::Document.new + report << RDoc::Markup::Paragraph.new('The following items are not documented:') + report << RDoc::Markup::BlankLine.new + + ucm.sort.each do |cm| + body = report_class_module(cm) { + [ + report_constants(cm), + report_attributes(cm), + report_methods(cm), + ].compact + } + + report << body if body + end + + if @coverage_level > 0 then + calculate + + return great_job if @num_items == @doc_items + end + + report + end + + ## + # Returns a report on undocumented attributes in ClassModule +cm+ + + def report_attributes cm + return if cm.attributes.empty? + + report = [] + + cm.each_attribute do |attr| + next if attr.documented? + line = attr.line ? ":#{attr.line}" : nil + report << " #{attr.definition} :#{attr.name} # in file #{attr.file.full_name}#{line}\n" + report << "\n" + end + + report + end + + ## + # Returns a report on undocumented items in ClassModule +cm+ + + def report_class_module cm + return if cm.fully_documented? and @coverage_level.zero? + return unless cm.display? + + report = RDoc::Markup::Document.new + + if cm.in_files.empty? then + report << RDoc::Markup::Paragraph.new("#{cm.definition} is referenced but empty.") + report << RDoc::Markup::Paragraph.new("It probably came from another project. I'm sorry I'm holding it against you.") + + return report + elsif cm.documented? then + documented = true + klass = RDoc::Markup::Verbatim.new("#{cm.definition} # is documented\n") + else + report << RDoc::Markup::Paragraph.new('In files:') + + list = RDoc::Markup::List.new :BULLET + + cm.in_files.each do |file| + para = RDoc::Markup::Paragraph.new file.full_name + list << RDoc::Markup::ListItem.new(nil, para) + end + + report << list + report << RDoc::Markup::BlankLine.new + + klass = RDoc::Markup::Verbatim.new("#{cm.definition}\n") + end + + klass << "\n" + + body = yield.flatten # HACK remove #flatten + + if body.empty? then + return if documented + + klass.parts.pop + else + klass.parts.concat body + end + + klass << "end\n" + + report << klass + + report + end + + ## + # Returns a report on undocumented constants in ClassModule +cm+ + + def report_constants cm + return if cm.constants.empty? + + report = [] + + cm.each_constant do |constant| + # TODO constant aliases are listed in the summary but not reported + # figure out what to do here + next if constant.documented? || constant.is_alias_for + + line = constant.line ? ":#{constant.line}" : line + report << " # in file #{constant.file.full_name}#{line}\n" + report << " #{constant.name} = nil\n" + report << "\n" + end + + report + end + + ## + # Returns a report on undocumented methods in ClassModule +cm+ + + def report_methods cm + return if cm.method_list.empty? + + report = [] + + cm.each_method do |method| + next if method.documented? and @coverage_level.zero? + + if @coverage_level > 0 then + params, undoc = undoc_params method + + @num_params += params + + unless undoc.empty? then + @undoc_params += undoc.length + + undoc = undoc.map do |param| "+#{param}+" end + param_report = " # #{undoc.join ', '} is not documented\n" + end + end + + next if method.documented? and not param_report + + line = method.line ? ":#{method.line}" : nil + scope = method.singleton ? 'self.' : nil + + report << " # in file #{method.file.full_name}#{line}\n" + report << param_report if param_report + report << " def #{scope}#{method.name}#{method.params}; end\n" + report << "\n" + end + + report + end + + ## + # Returns a summary of the collected statistics. + + def summary + calculate + + num_width = [@num_files, @num_items].max.to_s.length + undoc_width = [ + @undoc_attributes, + @undoc_classes, + @undoc_constants, + @undoc_items, + @undoc_methods, + @undoc_modules, + @undoc_params, + ].max.to_s.length + + report = RDoc::Markup::Verbatim.new + + report << "Files: %*d\n" % [num_width, @num_files] + + report << "\n" + + report << "Classes: %*d (%*d undocumented)\n" % [ + num_width, @num_classes, undoc_width, @undoc_classes] + report << "Modules: %*d (%*d undocumented)\n" % [ + num_width, @num_modules, undoc_width, @undoc_modules] + report << "Constants: %*d (%*d undocumented)\n" % [ + num_width, @num_constants, undoc_width, @undoc_constants] + report << "Attributes: %*d (%*d undocumented)\n" % [ + num_width, @num_attributes, undoc_width, @undoc_attributes] + report << "Methods: %*d (%*d undocumented)\n" % [ + num_width, @num_methods, undoc_width, @undoc_methods] + report << "Parameters: %*d (%*d undocumented)\n" % [ + num_width, @num_params, undoc_width, @undoc_params] if + @coverage_level > 0 + + report << "\n" + + report << "Total: %*d (%*d undocumented)\n" % [ + num_width, @num_items, undoc_width, @undoc_items] + + report << "%6.2f%% documented\n" % percent_doc + report << "\n" + report << "Elapsed: %0.1fs\n" % (Time.now - @start) + + RDoc::Markup::Document.new report + end + + ## + # Determines which parameters in +method+ were not documented. Returns a + # total parameter count and an Array of undocumented methods. + + def undoc_params method + @formatter ||= RDoc::Markup::ToTtOnly.new + + params = method.param_list + + params = params.map { |param| param.gsub(/^\*\*?/, '') } + + return 0, [] if params.empty? + + document = parse method.comment + + tts = document.accept @formatter + + undoc = params - tts + + [params.length, undoc] + end + + autoload :Quiet, 'rdoc/stats/quiet' + autoload :Normal, 'rdoc/stats/normal' + autoload :Verbose, 'rdoc/stats/verbose' + +end + diff --git a/jni/ruby/lib/rdoc/stats/normal.rb b/jni/ruby/lib/rdoc/stats/normal.rb new file mode 100644 index 0000000..ef366a5 --- /dev/null +++ b/jni/ruby/lib/rdoc/stats/normal.rb @@ -0,0 +1,59 @@ +begin + require 'io/console/size' +rescue LoadError +end + +## +# Stats printer that prints just the files being documented with a progress +# bar + +class RDoc::Stats::Normal < RDoc::Stats::Quiet + + def begin_adding # :nodoc: + puts "Parsing sources..." + @last_width = 0 + end + + ## + # Prints a file with a progress bar + + def print_file files_so_far, filename + progress_bar = sprintf("%3d%% [%2d/%2d] ", + 100 * files_so_far / @num_files, + files_so_far, + @num_files) + + # Print a progress bar, but make sure it fits on a single line. Filename + # will be truncated if necessary. + terminal_width = if defined?(IO) && IO.respond_to?(:console_size) + IO.console_size[1].to_i.nonzero? || 80 + else + 80 + end + max_filename_size = terminal_width - progress_bar.size + + if filename.size > max_filename_size then + # Turn "some_long_filename.rb" to "...ong_filename.rb" + filename = filename[(filename.size - max_filename_size) .. -1] + filename[0..2] = "..." + end + + line = "#{progress_bar}#{filename}" + if $stdout.tty? + # Clean the line with whitespaces so that leftover output from the + # previous line doesn't show up. + $stdout.print("\r" << (" " * @last_width) << ("\b" * @last_width) << "\r") if @last_width && @last_width > 0 + @last_width = line.size + $stdout.print("#{line}\r") + else + $stdout.puts(line) + end + $stdout.flush + end + + def done_adding # :nodoc: + puts + end + +end + diff --git a/jni/ruby/lib/rdoc/stats/quiet.rb b/jni/ruby/lib/rdoc/stats/quiet.rb new file mode 100644 index 0000000..eed27b2 --- /dev/null +++ b/jni/ruby/lib/rdoc/stats/quiet.rb @@ -0,0 +1,59 @@ +## +# Stats printer that prints nothing + +class RDoc::Stats::Quiet + + ## + # Creates a new Quiet that will print nothing + + def initialize num_files + @num_files = num_files + end + + ## + # Prints a message at the beginning of parsing + + def begin_adding(*) end + + ## + # Prints when an alias is added + + def print_alias(*) end + + ## + # Prints when an attribute is added + + def print_attribute(*) end + + ## + # Prints when a class is added + + def print_class(*) end + + ## + # Prints when a constant is added + + def print_constant(*) end + + ## + # Prints when a file is added + + def print_file(*) end + + ## + # Prints when a method is added + + def print_method(*) end + + ## + # Prints when a module is added + + def print_module(*) end + + ## + # Prints when RDoc is done + + def done_adding(*) end + +end + diff --git a/jni/ruby/lib/rdoc/stats/verbose.rb b/jni/ruby/lib/rdoc/stats/verbose.rb new file mode 100644 index 0000000..430809a --- /dev/null +++ b/jni/ruby/lib/rdoc/stats/verbose.rb @@ -0,0 +1,45 @@ +## +# Stats printer that prints everything documented, including the documented +# status + +class RDoc::Stats::Verbose < RDoc::Stats::Normal + + ## + # Returns a marker for RDoc::CodeObject +co+ being undocumented + + def nodoc co + " (undocumented)" unless co.documented? + end + + def print_alias as # :nodoc: + puts " alias #{as.new_name} #{as.old_name}#{nodoc as}" + end + + def print_attribute attribute # :nodoc: + puts " #{attribute.definition} #{attribute.name}#{nodoc attribute}" + end + + def print_class(klass) # :nodoc: + puts " class #{klass.full_name}#{nodoc klass}" + end + + def print_constant(constant) # :nodoc: + puts " #{constant.name}#{nodoc constant}" + end + + def print_file(files_so_far, file) # :nodoc: + super + puts + end + + def print_method(method) # :nodoc: + puts " #{method.singleton ? '::' : '#'}#{method.name}#{nodoc method}" + end + + def print_module(mod) # :nodoc: + puts " module #{mod.full_name}#{nodoc mod}" + end + +end + + diff --git a/jni/ruby/lib/rdoc/store.rb b/jni/ruby/lib/rdoc/store.rb new file mode 100644 index 0000000..fde6f06 --- /dev/null +++ b/jni/ruby/lib/rdoc/store.rb @@ -0,0 +1,979 @@ +require 'fileutils' + +## +# A set of rdoc data for a single project (gem, path, etc.). +# +# The store manages reading and writing ri data for a project and maintains a +# cache of methods, classes and ancestors in the store. +# +# The store maintains a #cache of its contents for faster lookup. After +# adding items to the store it must be flushed using #save_cache. The cache +# contains the following structures: +# +# @cache = { +# :ancestors => {}, # class name => ancestor names +# :attributes => {}, # class name => attributes +# :class_methods => {}, # class name => class methods +# :instance_methods => {}, # class name => instance methods +# :modules => [], # classes and modules in this store +# :pages => [], # page names +# } +#-- +# TODO need to prune classes + +class RDoc::Store + + ## + # Errors raised from loading or saving the store + + class Error < RDoc::Error + end + + ## + # Raised when a stored file for a class, module, page or method is missing. + + class MissingFileError < Error + + ## + # The store the file should exist in + + attr_reader :store + + ## + # The file the #name should be saved as + + attr_reader :file + + ## + # The name of the object the #file would be loaded from + + attr_reader :name + + ## + # Creates a new MissingFileError for the missing +file+ for the given + # +name+ that should have been in the +store+. + + def initialize store, file, name + @store = store + @file = file + @name = name + end + + def message # :nodoc: + "store at #{@store.path} missing file #{@file} for #{@name}" + end + + end + + ## + # Stores the name of the C variable a class belongs to. This helps wire up + # classes defined from C across files. + + attr_reader :c_enclosure_classes # :nodoc: + + attr_reader :c_enclosure_names # :nodoc: + + ## + # Maps C variables to class or module names for each parsed C file. + + attr_reader :c_class_variables + + ## + # Maps C variables to singleton class names for each parsed C file. + + attr_reader :c_singleton_class_variables + + ## + # If true this Store will not write any files + + attr_accessor :dry_run + + ## + # Path this store reads or writes + + attr_accessor :path + + ## + # The RDoc::RDoc driver for this parse tree. This allows classes consulting + # the documentation tree to access user-set options, for example. + + attr_accessor :rdoc + + ## + # Type of ri datastore this was loaded from. See RDoc::RI::Driver, + # RDoc::RI::Paths. + + attr_accessor :type + + ## + # The contents of the Store + + attr_reader :cache + + ## + # The encoding of the contents in the Store + + attr_accessor :encoding + + ## + # Creates a new Store of +type+ that will load or save to +path+ + + def initialize path = nil, type = nil + @dry_run = false + @encoding = nil + @path = path + @rdoc = nil + @type = type + + @cache = { + :ancestors => {}, + :attributes => {}, + :class_methods => {}, + :c_class_variables => {}, + :c_singleton_class_variables => {}, + :encoding => @encoding, + :instance_methods => {}, + :main => nil, + :modules => [], + :pages => [], + :title => nil, + } + + @classes_hash = {} + @modules_hash = {} + @files_hash = {} + + @c_enclosure_classes = {} + @c_enclosure_names = {} + + @c_class_variables = {} + @c_singleton_class_variables = {} + + @unique_classes = nil + @unique_modules = nil + end + + ## + # Adds +module+ as an enclosure (namespace) for the given +variable+ for C + # files. + + def add_c_enclosure variable, namespace + @c_enclosure_classes[variable] = namespace + end + + ## + # Adds C variables from an RDoc::Parser::C + + def add_c_variables c_parser + filename = c_parser.top_level.relative_name + + @c_class_variables[filename] = make_variable_map c_parser.classes + + @c_singleton_class_variables[filename] = c_parser.singleton_classes + end + + ## + # Adds the file with +name+ as an RDoc::TopLevel to the store. Returns the + # created RDoc::TopLevel. + + def add_file absolute_name, relative_name = absolute_name + unless top_level = @files_hash[relative_name] then + top_level = RDoc::TopLevel.new absolute_name, relative_name + top_level.store = self + @files_hash[relative_name] = top_level + end + + top_level + end + + ## + # Returns all classes discovered by RDoc + + def all_classes + @classes_hash.values + end + + ## + # Returns all classes and modules discovered by RDoc + + def all_classes_and_modules + @classes_hash.values + @modules_hash.values + end + + ## + # All TopLevels known to RDoc + + def all_files + @files_hash.values + end + + ## + # Returns all modules discovered by RDoc + + def all_modules + modules_hash.values + end + + ## + # Ancestors cache accessor. Maps a klass name to an Array of its ancestors + # in this store. If Foo in this store inherits from Object, Kernel won't be + # listed (it will be included from ruby's ri store). + + def ancestors + @cache[:ancestors] + end + + ## + # Attributes cache accessor. Maps a class to an Array of its attributes. + + def attributes + @cache[:attributes] + end + + ## + # Path to the cache file + + def cache_path + File.join @path, 'cache.ri' + end + + ## + # Path to the ri data for +klass_name+ + + def class_file klass_name + name = klass_name.split('::').last + File.join class_path(klass_name), "cdesc-#{name}.ri" + end + + ## + # Class methods cache accessor. Maps a class to an Array of its class + # methods (not full name). + + def class_methods + @cache[:class_methods] + end + + ## + # Path where data for +klass_name+ will be stored (methods or class data) + + def class_path klass_name + File.join @path, *klass_name.split('::') + end + + ## + # Hash of all classes known to RDoc + + def classes_hash + @classes_hash + end + + ## + # Removes empty items and ensures item in each collection are unique and + # sorted + + def clean_cache_collection collection # :nodoc: + collection.each do |name, item| + if item.empty? then + collection.delete name + else + # HACK mongrel-1.1.5 documents its files twice + item.uniq! + item.sort! + end + end + end + + ## + # Prepares the RDoc code object tree for use by a generator. + # + # It finds unique classes/modules defined, and replaces classes/modules that + # are aliases for another one by a copy with RDoc::ClassModule#is_alias_for + # set. + # + # It updates the RDoc::ClassModule#constant_aliases attribute of "real" + # classes or modules. + # + # It also completely removes the classes and modules that should be removed + # from the documentation and the methods that have a visibility below + # +min_visibility+, which is the <tt>--visibility</tt> option. + # + # See also RDoc::Context#remove_from_documentation? + + def complete min_visibility + fix_basic_object_inheritance + + # cache included modules before they are removed from the documentation + all_classes_and_modules.each { |cm| cm.ancestors } + + unless min_visibility == :nodoc then + remove_nodoc @classes_hash + remove_nodoc @modules_hash + end + + @unique_classes = find_unique @classes_hash + @unique_modules = find_unique @modules_hash + + unique_classes_and_modules.each do |cm| + cm.complete min_visibility + end + + @files_hash.each_key do |file_name| + tl = @files_hash[file_name] + + unless tl.text? then + tl.modules_hash.clear + tl.classes_hash.clear + + tl.classes_or_modules.each do |cm| + name = cm.full_name + if cm.type == 'class' then + tl.classes_hash[name] = cm if @classes_hash[name] + else + tl.modules_hash[name] = cm if @modules_hash[name] + end + end + end + end + end + + ## + # Hash of all files known to RDoc + + def files_hash + @files_hash + end + + ## + # Finds the enclosure (namespace) for the given C +variable+. + + def find_c_enclosure variable + @c_enclosure_classes.fetch variable do + break unless name = @c_enclosure_names[variable] + + mod = find_class_or_module name + + unless mod then + loaded_mod = load_class_data name + + file = loaded_mod.in_files.first + + return unless file # legacy data source + + file.store = self + + mod = file.add_module RDoc::NormalModule, name + end + + @c_enclosure_classes[variable] = mod + end + end + + ## + # Finds the class with +name+ in all discovered classes + + def find_class_named name + @classes_hash[name] + end + + ## + # Finds the class with +name+ starting in namespace +from+ + + def find_class_named_from name, from + from = find_class_named from unless RDoc::Context === from + + until RDoc::TopLevel === from do + return nil unless from + + klass = from.find_class_named name + return klass if klass + + from = from.parent + end + + find_class_named name + end + + ## + # Finds the class or module with +name+ + + def find_class_or_module name + name = $' if name =~ /^::/ + @classes_hash[name] || @modules_hash[name] + end + + ## + # Finds the file with +name+ in all discovered files + + def find_file_named name + @files_hash[name] + end + + ## + # Finds the module with +name+ in all discovered modules + + def find_module_named name + @modules_hash[name] + end + + ## + # Returns the RDoc::TopLevel that is a text file and has the given + # +file_name+ + + def find_text_page file_name + @files_hash.each_value.find do |file| + file.text? and file.full_name == file_name + end + end + + ## + # Finds unique classes/modules defined in +all_hash+, + # and returns them as an array. Performs the alias + # updates in +all_hash+: see ::complete. + #-- + # TODO aliases should be registered by Context#add_module_alias + + def find_unique all_hash + unique = [] + + all_hash.each_pair do |full_name, cm| + unique << cm if full_name == cm.full_name + end + + unique + end + + ## + # Fixes the erroneous <tt>BasicObject < Object</tt> in 1.9. + # + # Because we assumed all classes without a stated superclass + # inherit from Object, we have the above wrong inheritance. + # + # We fix BasicObject right away if we are running in a Ruby + # version >= 1.9. If not, we may be documenting 1.9 source + # while running under 1.8: we search the files of BasicObject + # for "object.c", and fix the inheritance if we find it. + + def fix_basic_object_inheritance + basic = classes_hash['BasicObject'] + return unless basic + if RUBY_VERSION >= '1.9' + basic.superclass = nil + elsif basic.in_files.any? { |f| File.basename(f.full_name) == 'object.c' } + basic.superclass = nil + end + end + + ## + # Friendly rendition of #path + + def friendly_path + case type + when :gem then + parent = File.expand_path '..', @path + "gem #{File.basename parent}" + when :home then '~/.rdoc' + when :site then 'ruby site' + when :system then 'ruby core' + else @path + end + end + + def inspect # :nodoc: + "#<%s:0x%x %s %p>" % [self.class, object_id, @path, module_names.sort] + end + + ## + # Instance methods cache accessor. Maps a class to an Array of its + # instance methods (not full name). + + def instance_methods + @cache[:instance_methods] + end + + ## + # Loads all items from this store into memory. This recreates a + # documentation tree for use by a generator + + def load_all + load_cache + + module_names.each do |module_name| + mod = find_class_or_module(module_name) || load_class(module_name) + + # load method documentation since the loaded class/module does not have + # it + loaded_methods = mod.method_list.map do |method| + load_method module_name, method.full_name + end + + mod.method_list.replace loaded_methods + + loaded_attributes = mod.attributes.map do |attribute| + load_method module_name, attribute.full_name + end + + mod.attributes.replace loaded_attributes + end + + all_classes_and_modules.each do |mod| + descendent_re = /^#{mod.full_name}::[^:]+$/ + + module_names.each do |name| + next unless name =~ descendent_re + + descendent = find_class_or_module name + + case descendent + when RDoc::NormalClass then + mod.classes_hash[name] = descendent + when RDoc::NormalModule then + mod.modules_hash[name] = descendent + end + end + end + + @cache[:pages].each do |page_name| + page = load_page page_name + @files_hash[page_name] = page + end + end + + ## + # Loads cache file for this store + + def load_cache + #orig_enc = @encoding + + open cache_path, 'rb' do |io| + @cache = Marshal.load io.read + end + + load_enc = @cache[:encoding] + + # TODO this feature will be time-consuming to add: + # a) Encodings may be incompatible but transcodeable + # b) Need to warn in the appropriate spots, wherever they may be + # c) Need to handle cross-cache differences in encodings + # d) Need to warn when generating into a cache with different encodings + # + #if orig_enc and load_enc != orig_enc then + # warn "Cached encoding #{load_enc} is incompatible with #{orig_enc}\n" \ + # "from #{path}/cache.ri" unless + # Encoding.compatible? orig_enc, load_enc + #end + + @encoding = load_enc unless @encoding + + @cache[:pages] ||= [] + @cache[:main] ||= nil + @cache[:c_class_variables] ||= {} + @cache[:c_singleton_class_variables] ||= {} + + @cache[:c_class_variables].each do |_, map| + map.each do |variable, name| + @c_enclosure_names[variable] = name + end + end + + @cache + rescue Errno::ENOENT + end + + ## + # Loads ri data for +klass_name+ and hooks it up to this store. + + def load_class klass_name + obj = load_class_data klass_name + + obj.store = self + + case obj + when RDoc::NormalClass then + @classes_hash[klass_name] = obj + when RDoc::NormalModule then + @modules_hash[klass_name] = obj + end + end + + ## + # Loads ri data for +klass_name+ + + def load_class_data klass_name + file = class_file klass_name + + open file, 'rb' do |io| + Marshal.load io.read + end + rescue Errno::ENOENT => e + error = MissingFileError.new(self, file, klass_name) + error.set_backtrace e.backtrace + raise error + end + + ## + # Loads ri data for +method_name+ in +klass_name+ + + def load_method klass_name, method_name + file = method_file klass_name, method_name + + open file, 'rb' do |io| + obj = Marshal.load io.read + obj.store = self + obj.parent = + find_class_or_module(klass_name) || load_class(klass_name) unless + obj.parent + obj + end + rescue Errno::ENOENT => e + error = MissingFileError.new(self, file, klass_name + method_name) + error.set_backtrace e.backtrace + raise error + end + + ## + # Loads ri data for +page_name+ + + def load_page page_name + file = page_file page_name + + open file, 'rb' do |io| + obj = Marshal.load io.read + obj.store = self + obj + end + rescue Errno::ENOENT => e + error = MissingFileError.new(self, file, page_name) + error.set_backtrace e.backtrace + raise error + end + + ## + # Gets the main page for this RDoc store. This page is used as the root of + # the RDoc server. + + def main + @cache[:main] + end + + ## + # Sets the main page for this RDoc store. + + def main= page + @cache[:main] = page + end + + ## + # Converts the variable => ClassModule map +variables+ from a C parser into + # a variable => class name map. + + def make_variable_map variables + map = {} + + variables.each { |variable, class_module| + map[variable] = class_module.full_name + } + + map + end + + ## + # Path to the ri data for +method_name+ in +klass_name+ + + def method_file klass_name, method_name + method_name = method_name.split('::').last + method_name =~ /#(.*)/ + method_type = $1 ? 'i' : 'c' + method_name = $1 if $1 + + method_name = if ''.respond_to? :ord then + method_name.gsub(/\W/) { "%%%02x" % $&[0].ord } + else + method_name.gsub(/\W/) { "%%%02x" % $&[0] } + end + + File.join class_path(klass_name), "#{method_name}-#{method_type}.ri" + end + + ## + # Modules cache accessor. An Array of all the module (and class) names in + # the store. + + def module_names + @cache[:modules] + end + + ## + # Hash of all modules known to RDoc + + def modules_hash + @modules_hash + end + + ## + # Returns the RDoc::TopLevel that is a text file and has the given +name+ + + def page name + @files_hash.each_value.find do |file| + file.text? and file.page_name == name + end + end + + ## + # Path to the ri data for +page_name+ + + def page_file page_name + file_name = File.basename(page_name).gsub('.', '_') + + File.join @path, File.dirname(page_name), "page-#{file_name}.ri" + end + + ## + # Removes from +all_hash+ the contexts that are nodoc or have no content. + # + # See RDoc::Context#remove_from_documentation? + + def remove_nodoc all_hash + all_hash.keys.each do |name| + context = all_hash[name] + all_hash.delete(name) if context.remove_from_documentation? + end + end + + ## + # Saves all entries in the store + + def save + load_cache + + all_classes_and_modules.each do |klass| + save_class klass + + klass.each_method do |method| + save_method klass, method + end + + klass.each_attribute do |attribute| + save_method klass, attribute + end + end + + all_files.each do |file| + save_page file + end + + save_cache + end + + ## + # Writes the cache file for this store + + def save_cache + clean_cache_collection @cache[:ancestors] + clean_cache_collection @cache[:attributes] + clean_cache_collection @cache[:class_methods] + clean_cache_collection @cache[:instance_methods] + + @cache[:modules].uniq! + @cache[:modules].sort! + + @cache[:pages].uniq! + @cache[:pages].sort! + + @cache[:encoding] = @encoding # this gets set twice due to assert_cache + + @cache[:c_class_variables].merge! @c_class_variables + @cache[:c_singleton_class_variables].merge! @c_singleton_class_variables + + return if @dry_run + + marshal = Marshal.dump @cache + + open cache_path, 'wb' do |io| + io.write marshal + end + end + + ## + # Writes the ri data for +klass+ (or module) + + def save_class klass + full_name = klass.full_name + + FileUtils.mkdir_p class_path(full_name) unless @dry_run + + @cache[:modules] << full_name + + path = class_file full_name + + begin + disk_klass = load_class full_name + + klass = disk_klass.merge klass + rescue MissingFileError + end + + # BasicObject has no ancestors + ancestors = klass.direct_ancestors.compact.map do |ancestor| + # HACK for classes we don't know about (class X < RuntimeError) + String === ancestor ? ancestor : ancestor.full_name + end + + @cache[:ancestors][full_name] ||= [] + @cache[:ancestors][full_name].concat ancestors + + attribute_definitions = klass.attributes.map do |attribute| + "#{attribute.definition} #{attribute.name}" + end + + unless attribute_definitions.empty? then + @cache[:attributes][full_name] ||= [] + @cache[:attributes][full_name].concat attribute_definitions + end + + to_delete = [] + + unless klass.method_list.empty? then + @cache[:class_methods][full_name] ||= [] + @cache[:instance_methods][full_name] ||= [] + + class_methods, instance_methods = + klass.method_list.partition { |meth| meth.singleton } + + class_methods = class_methods. map { |method| method.name } + instance_methods = instance_methods.map { |method| method.name } + attribute_names = klass.attributes.map { |attr| attr.name } + + old = @cache[:class_methods][full_name] - class_methods + to_delete.concat old.map { |method| + method_file full_name, "#{full_name}::#{method}" + } + + old = @cache[:instance_methods][full_name] - + instance_methods - attribute_names + to_delete.concat old.map { |method| + method_file full_name, "#{full_name}##{method}" + } + + @cache[:class_methods][full_name] = class_methods + @cache[:instance_methods][full_name] = instance_methods + end + + return if @dry_run + + FileUtils.rm_f to_delete + + marshal = Marshal.dump klass + + open path, 'wb' do |io| + io.write marshal + end + end + + ## + # Writes the ri data for +method+ on +klass+ + + def save_method klass, method + full_name = klass.full_name + + FileUtils.mkdir_p class_path(full_name) unless @dry_run + + cache = if method.singleton then + @cache[:class_methods] + else + @cache[:instance_methods] + end + cache[full_name] ||= [] + cache[full_name] << method.name + + return if @dry_run + + marshal = Marshal.dump method + + open method_file(full_name, method.full_name), 'wb' do |io| + io.write marshal + end + end + + ## + # Writes the ri data for +page+ + + def save_page page + return unless page.text? + + path = page_file page.full_name + + FileUtils.mkdir_p File.dirname(path) unless @dry_run + + cache[:pages] ||= [] + cache[:pages] << page.full_name + + return if @dry_run + + marshal = Marshal.dump page + + open path, 'wb' do |io| + io.write marshal + end + end + + ## + # Source of the contents of this store. + # + # For a store from a gem the source is the gem name. For a store from the + # home directory the source is "home". For system ri store (the standard + # library documentation) the source is"ruby". For a store from the site + # ri directory the store is "site". For other stores the source is the + # #path. + + def source + case type + when :gem then File.basename File.expand_path '..', @path + when :home then 'home' + when :site then 'site' + when :system then 'ruby' + else @path + end + end + + ## + # Gets the title for this RDoc store. This is used as the title in each + # page on the RDoc server + + def title + @cache[:title] + end + + ## + # Sets the title page for this RDoc store. + + def title= title + @cache[:title] = title + end + + ## + # Returns the unique classes discovered by RDoc. + # + # ::complete must have been called prior to using this method. + + def unique_classes + @unique_classes + end + + ## + # Returns the unique classes and modules discovered by RDoc. + # ::complete must have been called prior to using this method. + + def unique_classes_and_modules + @unique_classes + @unique_modules + end + + ## + # Returns the unique modules discovered by RDoc. + # ::complete must have been called prior to using this method. + + def unique_modules + @unique_modules + end + +end + diff --git a/jni/ruby/lib/rdoc/task.rb b/jni/ruby/lib/rdoc/task.rb new file mode 100644 index 0000000..a839390 --- /dev/null +++ b/jni/ruby/lib/rdoc/task.rb @@ -0,0 +1,330 @@ +#-- +# Copyright (c) 2003, 2004 Jim Weirich, 2009 Eric Hodel +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +#++ + +require 'rubygems' +begin + gem 'rdoc' +rescue Gem::LoadError +end unless defined?(RDoc) + +begin + gem 'rake' +rescue Gem::LoadError +end unless defined?(Rake) + +require 'rdoc' +require 'rake' +require 'rake/tasklib' + +## +# RDoc::Task creates the following rake tasks to generate and clean up RDoc +# output: +# +# [rdoc] +# Main task for this RDoc task. +# +# [clobber_rdoc] +# Delete all the rdoc files. This target is automatically added to the main +# clobber target. +# +# [rerdoc] +# Rebuild the rdoc files from scratch, even if they are not out of date. +# +# Simple Example: +# +# require 'rdoc/task' +# +# RDoc::Task.new do |rdoc| +# rdoc.main = "README.rdoc" +# rdoc.rdoc_files.include("README.rdoc", "lib/**/*.rb") +# end +# +# The +rdoc+ object passed to the block is an RDoc::Task object. See the +# attributes list for the RDoc::Task class for available customization options. +# +# == Specifying different task names +# +# You may wish to give the task a different name, such as if you are +# generating two sets of documentation. For instance, if you want to have a +# development set of documentation including private methods: +# +# require 'rdoc/task' +# +# RDoc::Task.new :rdoc_dev do |rdoc| +# rdoc.main = "README.doc" +# rdoc.rdoc_files.include("README.rdoc", "lib/**/*.rb") +# rdoc.options << "--all" +# end +# +# The tasks would then be named :<em>rdoc_dev</em>, +# :clobber_<em>rdoc_dev</em>, and :re<em>rdoc_dev</em>. +# +# If you wish to have completely different task names, then pass a Hash as +# first argument. With the <tt>:rdoc</tt>, <tt>:clobber_rdoc</tt> and +# <tt>:rerdoc</tt> options, you can customize the task names to your liking. +# +# For example: +# +# require 'rdoc/task' +# +# RDoc::Task.new(:rdoc => "rdoc", :clobber_rdoc => "rdoc:clean", +# :rerdoc => "rdoc:force") +# +# This will create the tasks <tt>:rdoc</tt>, <tt>:rdoc:clean</tt> and +# <tt>:rdoc:force</tt>. + +class RDoc::Task < Rake::TaskLib + + ## + # Name of the main, top level task. (default is :rdoc) + + attr_accessor :name + + ## + # Comment markup format. rdoc, rd and tomdoc are supported. (default is + # 'rdoc') + + attr_accessor :markup + + ## + # Name of directory to receive the html output files. (default is "html") + + attr_accessor :rdoc_dir + + ## + # Title of RDoc documentation. (defaults to rdoc's default) + + attr_accessor :title + + ## + # Name of file to be used as the main, top level file of the RDoc. (default + # is none) + + attr_accessor :main + + ## + # Name of template to be used by rdoc. (defaults to rdoc's default) + + attr_accessor :template + + ## + # Name of format generator (<tt>--format<tt>) used by rdoc. (defaults to + # rdoc's default) + + attr_accessor :generator + + ## + # List of files to be included in the rdoc generation. (default is []) + + attr_accessor :rdoc_files + + ## + # Additional list of options to be passed rdoc. (default is []) + + attr_accessor :options + + ## + # Whether to run the rdoc process as an external shell (default is false) + + attr_accessor :external + + ## + # Create an RDoc task with the given name. See the RDoc::Task class overview + # for documentation. + + def initialize name = :rdoc # :yield: self + defaults + + check_names name + + @name = name + + yield self if block_given? + + define + end + + ## + # Ensures that +names+ only includes names for the :rdoc, :clobber_rdoc and + # :rerdoc. If other names are given an ArgumentError is raised. + + def check_names names + return unless Hash === names + + invalid_options = + names.keys.map { |k| k.to_sym } - [:rdoc, :clobber_rdoc, :rerdoc] + + unless invalid_options.empty? then + raise ArgumentError, "invalid options: #{invalid_options.join ', '}" + end + end + + ## + # Task description for the clobber rdoc task or its renamed equivalent + + def clobber_task_description + "Remove RDoc HTML files" + end + + ## + # Sets default task values + + def defaults + @name = :rdoc + @rdoc_files = Rake::FileList.new + @rdoc_dir = 'html' + @main = nil + @title = nil + @template = nil + @generator = nil + @options = [] + end + + ## + # All source is inline now. This method is deprecated + + def inline_source # :nodoc: + warn "RDoc::Task#inline_source is deprecated" + true + end + + ## + # All source is inline now. This method is deprecated + + def inline_source=(value) # :nodoc: + warn "RDoc::Task#inline_source is deprecated" + end + + ## + # Create the tasks defined by this task lib. + + def define + desc rdoc_task_description + task rdoc_task_name + + desc rerdoc_task_description + task rerdoc_task_name => [clobber_task_name, rdoc_task_name] + + desc clobber_task_description + task clobber_task_name do + rm_r @rdoc_dir rescue nil + end + + task :clobber => [clobber_task_name] + + directory @rdoc_dir + + rdoc_target_deps = [ + @rdoc_files, + Rake.application.rakefile + ].flatten.compact + + task rdoc_task_name => [rdoc_target] + file rdoc_target => rdoc_target_deps do + @before_running_rdoc.call if @before_running_rdoc + args = option_list + @rdoc_files + + $stderr.puts "rdoc #{args.join ' '}" if Rake.application.options.trace + RDoc::RDoc.new.document args + end + + self + end + + ## + # List of options that will be supplied to RDoc + + def option_list + result = @options.dup + result << "-o" << @rdoc_dir + result << "--main" << main if main + result << "--markup" << markup if markup + result << "--title" << title if title + result << "-T" << template if template + result << '-f' << generator if generator + result + end + + ## + # The block passed to this method will be called just before running the + # RDoc generator. It is allowed to modify RDoc::Task attributes inside the + # block. + + def before_running_rdoc(&block) + @before_running_rdoc = block + end + + ## + # Task description for the rdoc task or its renamed equivalent + + def rdoc_task_description + 'Build RDoc HTML files' + end + + ## + # Task description for the rerdoc task or its renamed description + + def rerdoc_task_description + "Rebuild RDoc HTML files" + end + + private + + def rdoc_target + "#{rdoc_dir}/created.rid" + end + + def rdoc_task_name + case name + when Hash then (name[:rdoc] || "rdoc").to_s + else name.to_s + end + end + + def clobber_task_name + case name + when Hash then (name[:clobber_rdoc] || "clobber_rdoc").to_s + else "clobber_#{name}" + end + end + + def rerdoc_task_name + case name + when Hash then (name[:rerdoc] || "rerdoc").to_s + else "re#{name}" + end + end + +end + +# :stopdoc: +module Rake + + ## + # For backwards compatibility + + RDocTask = RDoc::Task + +end +# :startdoc: + diff --git a/jni/ruby/lib/rdoc/test_case.rb b/jni/ruby/lib/rdoc/test_case.rb new file mode 100644 index 0000000..4989516 --- /dev/null +++ b/jni/ruby/lib/rdoc/test_case.rb @@ -0,0 +1,217 @@ +require 'rubygems' + +begin + gem 'minitest', '~> 4.0' unless defined?(Test::Unit) +rescue NoMethodError, Gem::LoadError + # for ruby tests +end + +require 'minitest/autorun' +require 'minitest/benchmark' if ENV['BENCHMARK'] + +require 'fileutils' +require 'pp' +require 'tempfile' +require 'tmpdir' +require 'stringio' + +require 'rdoc' + +## +# RDoc::TestCase is an abstract TestCase to provide common setup and teardown +# across all RDoc tests. The test case uses minitest, so all the assertions +# of minitest may be used. +# +# The testcase provides the following: +# +# * A reset code-object tree +# * A reset markup preprocessor (RDoc::Markup::PreProcess) +# * The <code>@RM</code> alias of RDoc::Markup (for less typing) +# * <code>@pwd</code> containing the current working directory +# * FileUtils, pp, Tempfile, Dir.tmpdir and StringIO + +class RDoc::TestCase < MiniTest::Unit::TestCase + + ## + # Abstract test-case setup + + def setup + super + + @top_level = nil + + @have_encoding = Object.const_defined? :Encoding + + @RM = RDoc::Markup + + RDoc::Markup::PreProcess.reset + + @pwd = Dir.pwd + + @store = RDoc::Store.new + + @rdoc = RDoc::RDoc.new + @rdoc.store = @store + @rdoc.options = RDoc::Options.new + + g = Object.new + def g.class_dir() end + def g.file_dir() end + @rdoc.generator = g + end + + ## + # Asserts +path+ is a file + + def assert_file path + assert File.file?(path), "#{path} is not a file" + end + + ## + # Asserts +path+ is a directory + + def assert_directory path + assert File.directory?(path), "#{path} is not a directory" + end + + ## + # Refutes +path+ exists + + def refute_file path + refute File.exist?(path), "#{path} exists" + end + + ## + # Shortcut for RDoc::Markup::BlankLine.new + + def blank_line + @RM::BlankLine.new + end + + ## + # Shortcut for RDoc::Markup::BlockQuote.new with +contents+ + + def block *contents + @RM::BlockQuote.new(*contents) + end + + ## + # Creates an RDoc::Comment with +text+ which was defined on +top_level+. + # By default the comment has the 'rdoc' format. + + def comment text, top_level = @top_level + RDoc::Comment.new text, top_level + end + + ## + # Shortcut for RDoc::Markup::Document.new with +contents+ + + def doc *contents + @RM::Document.new(*contents) + end + + ## + # Shortcut for RDoc::Markup::HardBreak.new + + def hard_break + @RM::HardBreak.new + end + + ## + # Shortcut for RDoc::Markup::Heading.new with +level+ and +text+ + + def head level, text + @RM::Heading.new level, text + end + + ## + # Shortcut for RDoc::Markup::ListItem.new with +label+ and +parts+ + + def item label = nil, *parts + @RM::ListItem.new label, *parts + end + + ## + # Shortcut for RDoc::Markup::List.new with +type+ and +items+ + + def list type = nil, *items + @RM::List.new type, *items + end + + ## + # Enables pretty-print output + + def mu_pp obj # :nodoc: + s = '' + s = PP.pp obj, s + s = s.force_encoding Encoding.default_external if defined? Encoding + s.chomp + end + + ## + # Shortcut for RDoc::Markup::Paragraph.new with +contents+ + + def para *a + @RM::Paragraph.new(*a) + end + + ## + # Shortcut for RDoc::Markup::Rule.new with +weight+ + + def rule weight + @RM::Rule.new weight + end + + ## + # Shortcut for RDoc::Markup::Raw.new with +contents+ + + def raw *contents + @RM::Raw.new(*contents) + end + + ## + # Creates a temporary directory changes the current directory to it for the + # duration of the block. + # + # Depends upon Dir.mktmpdir + + def temp_dir + skip "No Dir::mktmpdir, upgrade your ruby" unless Dir.respond_to? :mktmpdir + + Dir.mktmpdir do |temp_dir| + Dir.chdir temp_dir do + yield temp_dir + end + end + end + + ## + # Shortcut for RDoc::Markup::Verbatim.new with +parts+ + + def verb *parts + @RM::Verbatim.new(*parts) + end + + ## + # run capture_io with setting $VERBOSE = true + + def verbose_capture_io + capture_io do + begin + orig_verbose = $VERBOSE + $VERBOSE = true + yield + ensure + $VERBOSE = orig_verbose + end + end + end +end + +# This hack allows autoload to work when Dir.pwd is changed for Ruby 1.8 since +# -I paths are not expanded. +$LOAD_PATH.each do |load_path| + break if load_path[0] == ?/ + load_path.replace File.expand_path load_path +end if RUBY_VERSION < '1.9' + diff --git a/jni/ruby/lib/rdoc/text.rb b/jni/ruby/lib/rdoc/text.rb new file mode 100644 index 0000000..606f15e --- /dev/null +++ b/jni/ruby/lib/rdoc/text.rb @@ -0,0 +1,324 @@ +# coding: utf-8 + +## +# For RDoc::Text#to_html + +require 'strscan' + +## +# For RDoc::Text#snippet + +begin + gem 'json' +rescue Gem::LoadError +end + +require 'json' + +## +# Methods for manipulating comment text + +module RDoc::Text + + ## + # Maps markup formats to classes that can parse them. If the format is + # unknown, "rdoc" format is used. + + MARKUP_FORMAT = { + 'markdown' => RDoc::Markdown, + 'rdoc' => RDoc::Markup, + 'rd' => RDoc::RD, + 'tomdoc' => RDoc::TomDoc, + } + + MARKUP_FORMAT.default = RDoc::Markup + + ## + # Maps an encoding to a Hash of characters properly transcoded for that + # encoding. + # + # See also encode_fallback. + + TO_HTML_CHARACTERS = Hash.new do |h, encoding| + h[encoding] = { + :close_dquote => encode_fallback('”', encoding, '"'), + :close_squote => encode_fallback('’', encoding, '\''), + :copyright => encode_fallback('©', encoding, '(c)'), + :ellipsis => encode_fallback('…', encoding, '...'), + :em_dash => encode_fallback('—', encoding, '---'), + :en_dash => encode_fallback('–', encoding, '--'), + :open_dquote => encode_fallback('“', encoding, '"'), + :open_squote => encode_fallback('‘', encoding, '\''), + :trademark => encode_fallback('®', encoding, '(r)'), + } + end if Object.const_defined? :Encoding + + ## + # Transcodes +character+ to +encoding+ with a +fallback+ character. + + def self.encode_fallback character, encoding, fallback + character.encode(encoding, :fallback => { character => fallback }, + :undef => :replace, :replace => fallback) + end + + ## + # Expands tab characters in +text+ to eight spaces + + def expand_tabs text + expanded = [] + + text.each_line do |line| + nil while line.gsub!(/(?:\G|\r)((?:.{8})*?)([^\t\r\n]{0,7})\t/) do + r = "#{$1}#{$2}#{' ' * (8 - $2.size)}" + r.force_encoding text.encoding if Object.const_defined? :Encoding + r + end + + expanded << line + end + + expanded.join + end + + ## + # Flush +text+ left based on the shortest line + + def flush_left text + indent = 9999 + + text.each_line do |line| + line_indent = line =~ /\S/ || 9999 + indent = line_indent if indent > line_indent + end + + empty = '' + empty.force_encoding text.encoding if Object.const_defined? :Encoding + + text.gsub(/^ {0,#{indent}}/, empty) + end + + ## + # Convert a string in markup format into HTML. + # + # Requires the including class to implement #formatter + + def markup text + if @store.rdoc.options + locale = @store.rdoc.options.locale + else + locale = nil + end + if locale + i18n_text = RDoc::I18n::Text.new(text) + text = i18n_text.translate(locale) + end + parse(text).accept formatter + end + + ## + # Strips hashes, expands tabs then flushes +text+ to the left + + def normalize_comment text + return text if text.empty? + + text = strip_stars text + text = strip_hashes text + text = expand_tabs text + text = flush_left text + text = strip_newlines text + text + end + + ## + # Normalizes +text+ then builds a RDoc::Markup::Document from it + + def parse text, format = 'rdoc' + return text if RDoc::Markup::Document === text + return text.parse if RDoc::Comment === text + + text = normalize_comment text # TODO remove, should not be necessary + + return RDoc::Markup::Document.new if text =~ /\A\n*\z/ + + MARKUP_FORMAT[format].parse text + end + + ## + # The first +limit+ characters of +text+ as HTML + + def snippet text, limit = 100 + document = parse text + + RDoc::Markup::ToHtmlSnippet.new(options, limit).convert document + end + + ## + # Strips leading # characters from +text+ + + def strip_hashes text + return text if text =~ /^(?>\s*)[^\#]/ + + empty = '' + empty.force_encoding text.encoding if Object.const_defined? :Encoding + + text.gsub(/^\s*(#+)/) { $1.tr '#', ' ' }.gsub(/^\s+$/, empty) + end + + ## + # Strips leading and trailing \n characters from +text+ + + def strip_newlines text + text.gsub(/\A\n*(.*?)\n*\z/m) do $1 end # block preserves String encoding + end + + ## + # Strips /* */ style comments + + def strip_stars text + return text unless text =~ %r%/\*.*\*/%m + + encoding = text.encoding if Object.const_defined? :Encoding + + text = text.gsub %r%Document-method:\s+[\w:.#=!?]+%, '' + + space = ' ' + space.force_encoding encoding if encoding + + text.sub! %r%/\*+% do space * $&.length end + text.sub! %r%\*+/% do space * $&.length end + text.gsub! %r%^[ \t]*\*%m do space * $&.length end + + empty = '' + empty.force_encoding encoding if encoding + text.gsub(/^\s+$/, empty) + end + + ## + # Converts ampersand, dashes, ellipsis, quotes, copyright and registered + # trademark symbols in +text+ to properly encoded characters. + + def to_html text + if Object.const_defined? :Encoding then + html = ''.encode text.encoding + + encoded = RDoc::Text::TO_HTML_CHARACTERS[text.encoding] + else + html = '' + encoded = { + :close_dquote => '”', + :close_squote => '’', + :copyright => '©', + :ellipsis => '…', + :em_dash => '—', + :en_dash => '–', + :open_dquote => '“', + :open_squote => '‘', + :trademark => '®', + } + end + + s = StringScanner.new text + insquotes = false + indquotes = false + after_word = nil + + until s.eos? do + case + when s.scan(/<(tt|code)>.*?<\/\1>/) then # skip contents of tt + html << s.matched.gsub('\\\\', '\\') + when s.scan(/<(tt|code)>.*?/) then + warn "mismatched <#{s[1]}> tag" # TODO signal file/line + html << s.matched + when s.scan(/<[^>]+\/?s*>/) then # skip HTML tags + html << s.matched + when s.scan(/\\(\S)/) then # unhandled suppressed crossref + html << s[1] + after_word = nil + when s.scan(/\.\.\.(\.?)/) then + html << s[1] << encoded[:ellipsis] + after_word = nil + when s.scan(/\(c\)/) then + html << encoded[:copyright] + after_word = nil + when s.scan(/\(r\)/) then + html << encoded[:trademark] + after_word = nil + when s.scan(/---/) then + html << encoded[:em_dash] + after_word = nil + when s.scan(/--/) then + html << encoded[:en_dash] + after_word = nil + when s.scan(/"|"/) then + html << encoded[indquotes ? :close_dquote : :open_dquote] + indquotes = !indquotes + after_word = nil + when s.scan(/``/) then # backtick double quote + html << encoded[:open_dquote] + after_word = nil + when s.scan(/''/) then # tick double quote + html << encoded[:close_dquote] + after_word = nil + when s.scan(/'/) then # single quote + if insquotes + html << encoded[:close_squote] + insquotes = false + elsif after_word + # Mary's dog, my parents' house: do not start paired quotes + html << encoded[:close_squote] + else + html << encoded[:open_squote] + insquotes = true + end + + after_word = nil + else # advance to the next potentially significant character + match = s.scan(/.+?(?=[<\\.("'`&-])/) #" + + if match then + html << match + after_word = match =~ /\w$/ + else + html << s.rest + break + end + end + end + + html + end + + ## + # Wraps +txt+ to +line_len+ + + def wrap(txt, line_len = 76) + res = [] + sp = 0 + ep = txt.length + + while sp < ep + # scan back for a space + p = sp + line_len - 1 + if p >= ep + p = ep + else + while p > sp and txt[p] != ?\s + p -= 1 + end + if p <= sp + p = sp + line_len + while p < ep and txt[p] != ?\s + p += 1 + end + end + end + res << txt[sp...p] << "\n" + sp = p + sp += 1 while sp < ep and txt[sp] == ?\s + end + + res.join.strip + end + +end + diff --git a/jni/ruby/lib/rdoc/token_stream.rb b/jni/ruby/lib/rdoc/token_stream.rb new file mode 100644 index 0000000..b46b7da --- /dev/null +++ b/jni/ruby/lib/rdoc/token_stream.rb @@ -0,0 +1,95 @@ +## +# A TokenStream is a list of tokens, gathered during the parse of some entity +# (say a method). Entities populate these streams by being registered with the +# lexer. Any class can collect tokens by including TokenStream. From the +# outside, you use such an object by calling the start_collecting_tokens +# method, followed by calls to add_token and pop_token. + +module RDoc::TokenStream + + ## + # Converts +token_stream+ to HTML wrapping various tokens with + # <tt><span></tt> elements. The following tokens types are wrapped in spans + # with the given class names: + # + # TkCONSTANT :: 'ruby-constant' + # TkKW :: 'ruby-keyword' + # TkIVAR :: 'ruby-ivar' + # TkOp :: 'ruby-operator' + # TkId :: 'ruby-identifier' + # TkNode :: 'ruby-node' + # TkCOMMENT :: 'ruby-comment' + # TkREGEXP :: 'ruby-regexp' + # TkSTRING :: 'ruby-string' + # TkVal :: 'ruby-value' + # + # Other token types are not wrapped in spans. + + def self.to_html token_stream + token_stream.map do |t| + next unless t + + style = case t + when RDoc::RubyToken::TkCONSTANT then 'ruby-constant' + when RDoc::RubyToken::TkKW then 'ruby-keyword' + when RDoc::RubyToken::TkIVAR then 'ruby-ivar' + when RDoc::RubyToken::TkOp then 'ruby-operator' + when RDoc::RubyToken::TkId then 'ruby-identifier' + when RDoc::RubyToken::TkNode then 'ruby-node' + when RDoc::RubyToken::TkCOMMENT then 'ruby-comment' + when RDoc::RubyToken::TkREGEXP then 'ruby-regexp' + when RDoc::RubyToken::TkSTRING then 'ruby-string' + when RDoc::RubyToken::TkVal then 'ruby-value' + end + + text = CGI.escapeHTML t.text + + if style then + "<span class=\"#{style}\">#{text}</span>" + else + text + end + end.join + end + + ## + # Adds +tokens+ to the collected tokens + + def add_tokens(*tokens) + tokens.flatten.each { |token| @token_stream << token } + end + + alias add_token add_tokens + + ## + # Starts collecting tokens + + def collect_tokens + @token_stream = [] + end + + alias start_collecting_tokens collect_tokens + + ## + # Remove the last token from the collected tokens + + def pop_token + @token_stream.pop + end + + ## + # Current token stream + + def token_stream + @token_stream + end + + ## + # Returns a string representation of the token stream + + def tokens_to_s + token_stream.compact.map { |token| token.text }.join '' + end + +end + diff --git a/jni/ruby/lib/rdoc/tom_doc.rb b/jni/ruby/lib/rdoc/tom_doc.rb new file mode 100644 index 0000000..2b62243 --- /dev/null +++ b/jni/ruby/lib/rdoc/tom_doc.rb @@ -0,0 +1,257 @@ +# :markup: tomdoc + +# A parser for TomDoc based on TomDoc 1.0.0-rc1 (02adef9b5a) +# +# The TomDoc specification can be found at: +# +# http://tomdoc.org +# +# The latest version of the TomDoc specification can be found at: +# +# https://github.com/mojombo/tomdoc/blob/master/tomdoc.md +# +# To choose TomDoc as your only default format see RDoc::Options@Saved+Options +# for instructions on setting up a <code>.rdoc_options</code> file to store +# your project default. +# +# There are a few differences between this parser and the specification. A +# best-effort was made to follow the specification as closely as possible but +# some choices to deviate were made. +# +# A future version of RDoc will warn when a MUST or MUST NOT is violated and +# may warn when a SHOULD or SHOULD NOT is violated. RDoc will always try +# to emit documentation even if given invalid TomDoc. +# +# Here are some implementation choices this parser currently makes: +# +# This parser allows rdoc-style inline markup but you should not depended on +# it. +# +# This parser allows a space between the comment and the method body. +# +# This parser does not require the default value to be described for an +# optional argument. +# +# This parser does not examine the order of sections. An Examples section may +# precede the Arguments section. +# +# This class is documented in TomDoc format. Since this is a subclass of the +# RDoc markup parser there isn't much to see here, unfortunately. + +class RDoc::TomDoc < RDoc::Markup::Parser + + # Internal: Token accessor + + attr_reader :tokens + + # Internal: Adds a post-processor which sets the RDoc section based on the + # comment's status. + # + # Returns nothing. + + def self.add_post_processor # :nodoc: + RDoc::Markup::PreProcess.post_process do |comment, code_object| + next unless code_object and + RDoc::Comment === comment and comment.format == 'tomdoc' + + comment.text.gsub!(/(\A\s*# )(Public|Internal|Deprecated):\s+/) do + section = code_object.add_section $2 + code_object.temporary_section = section + + $1 + end + end + end + + add_post_processor + + # Public: Parses TomDoc from text + # + # text - A String containing TomDoc-format text. + # + # Examples + # + # RDoc::TomDoc.parse <<-TOMDOC + # This method does some things + # + # Returns nothing. + # TOMDOC + # # => #<RDoc::Markup::Document:0xXXX @parts=[...], @file=nil> + # + # Returns an RDoc::Markup::Document representing the TomDoc format. + + def self.parse text + parser = new + + parser.tokenize text + doc = RDoc::Markup::Document.new + parser.parse doc + doc + end + + # Internal: Extracts the Signature section's method signature + # + # comment - An RDoc::Comment that will be parsed and have the signature + # extracted + # + # Returns a String containing the signature and nil if not + + def self.signature comment + return unless comment.tomdoc? + + document = comment.parse + + signature = nil + found_heading = false + found_signature = false + + document.parts.delete_if do |part| + next false if found_signature + + found_heading ||= + RDoc::Markup::Heading === part && part.text == 'Signature' + + next false unless found_heading + + next true if RDoc::Markup::BlankLine === part + + if RDoc::Markup::Verbatim === part then + signature = part + found_signature = true + end + end + + signature and signature.text + end + + # Public: Creates a new TomDoc parser. See also RDoc::Markup::parse + + def initialize + super + + @section = nil + @seen_returns = false + end + + # Internal: Builds a heading from the token stream + # + # level - The level of heading to create + # + # Returns an RDoc::Markup::Heading + + def build_heading level + heading = super + + @section = heading.text + + heading + end + + # Internal: Builds a verbatim from the token stream. A verbatim in the + # Examples section will be marked as in Ruby format. + # + # margin - The indentation from the margin for lines that belong to this + # verbatim section. + # + # Returns an RDoc::Markup::Verbatim + + def build_verbatim margin + verbatim = super + + verbatim.format = :ruby if @section == 'Examples' + + verbatim + end + + # Internal: Builds a paragraph from the token stream + # + # margin - Unused + # + # Returns an RDoc::Markup::Paragraph. + + def build_paragraph margin + p :paragraph_start => margin if @debug + + paragraph = RDoc::Markup::Paragraph.new + + until @tokens.empty? do + type, data, = get + + case type + when :TEXT then + @section = 'Returns' if data =~ /\AReturns/ + + paragraph << data + when :NEWLINE then + if :TEXT == peek_token[0] then + paragraph << ' ' + else + break + end + else + unget + break + end + end + + p :paragraph_end => margin if @debug + + paragraph + end + + ## + # Detects a section change to "Returns" and adds a heading + + def parse_text parent, indent # :nodoc: + paragraph = build_paragraph indent + + if false == @seen_returns and 'Returns' == @section then + @seen_returns = true + parent << RDoc::Markup::Heading.new(3, 'Returns') + parent << RDoc::Markup::BlankLine.new + end + + parent << paragraph + end + + # Internal: Turns text into an Array of tokens + # + # text - A String containing TomDoc-format text. + # + # Returns self. + + def tokenize text + text.sub!(/\A(Public|Internal|Deprecated):\s+/, '') + + setup_scanner text + + until @s.eos? do + pos = @s.pos + + # leading spaces will be reflected by the column of the next token + # the only thing we loose are trailing spaces at the end of the file + next if @s.scan(/ +/) + + @tokens << case + when @s.scan(/\r?\n/) then + token = [:NEWLINE, @s.matched, *token_pos(pos)] + @line_pos = char_pos @s.pos + @line += 1 + token + when @s.scan(/(Examples|Signature)$/) then + @tokens << [:HEADER, 3, *token_pos(pos)] + + [:TEXT, @s[1], *token_pos(pos)] + when @s.scan(/([:\w][\w\[\]]*)[ ]+- /) then + [:NOTE, @s[1], *token_pos(pos)] + else + @s.scan(/.*/) + [:TEXT, @s.matched.sub(/\r$/, ''), *token_pos(pos)] + end + end + + self + end + +end + diff --git a/jni/ruby/lib/rdoc/top_level.rb b/jni/ruby/lib/rdoc/top_level.rb new file mode 100644 index 0000000..64d81d2 --- /dev/null +++ b/jni/ruby/lib/rdoc/top_level.rb @@ -0,0 +1,282 @@ +## +# A TopLevel context is a representation of the contents of a single file + +class RDoc::TopLevel < RDoc::Context + + MARSHAL_VERSION = 0 # :nodoc: + + ## + # This TopLevel's File::Stat struct + + attr_accessor :file_stat + + ## + # Relative name of this file + + attr_accessor :relative_name + + ## + # Absolute name of this file + + attr_accessor :absolute_name + + ## + # All the classes or modules that were declared in + # this file. These are assigned to either +#classes_hash+ + # or +#modules_hash+ once we know what they really are. + + attr_reader :classes_or_modules + + attr_accessor :diagram # :nodoc: + + ## + # The parser class that processed this file + + attr_accessor :parser + + ## + # Creates a new TopLevel for the file at +absolute_name+. If documentation + # is being generated outside the source dir +relative_name+ is relative to + # the source directory. + + def initialize absolute_name, relative_name = absolute_name + super() + @name = nil + @absolute_name = absolute_name + @relative_name = relative_name + @file_stat = File.stat(absolute_name) rescue nil # HACK for testing + @diagram = nil + @parser = nil + + @classes_or_modules = [] + end + + ## + # An RDoc::TopLevel is equal to another with the same relative_name + + def == other + self.class === other and @relative_name == other.relative_name + end + + alias eql? == + + ## + # Adds +an_alias+ to +Object+ instead of +self+. + + def add_alias(an_alias) + object_class.record_location self + return an_alias unless @document_self + object_class.add_alias an_alias + end + + ## + # Adds +constant+ to +Object+ instead of +self+. + + def add_constant constant + object_class.record_location self + return constant unless @document_self + object_class.add_constant constant + end + + ## + # Adds +include+ to +Object+ instead of +self+. + + def add_include(include) + object_class.record_location self + return include unless @document_self + object_class.add_include include + end + + ## + # Adds +method+ to +Object+ instead of +self+. + + def add_method(method) + object_class.record_location self + return method unless @document_self + object_class.add_method method + end + + ## + # Adds class or module +mod+. Used in the building phase + # by the Ruby parser. + + def add_to_classes_or_modules mod + @classes_or_modules << mod + end + + ## + # Base name of this file + + def base_name + File.basename @relative_name + end + + alias name base_name + + ## + # Only a TopLevel that contains text file) will be displayed. See also + # RDoc::CodeObject#display? + + def display? + text? and super + end + + ## + # See RDoc::TopLevel::find_class_or_module + #-- + # TODO Why do we search through all classes/modules found, not just the + # ones of this instance? + + def find_class_or_module name + @store.find_class_or_module name + end + + ## + # Finds a class or module named +symbol+ + + def find_local_symbol(symbol) + find_class_or_module(symbol) || super + end + + ## + # Finds a module or class with +name+ + + def find_module_named(name) + find_class_or_module(name) + end + + ## + # Returns the relative name of this file + + def full_name + @relative_name + end + + ## + # An RDoc::TopLevel has the same hash as another with the same + # relative_name + + def hash + @relative_name.hash + end + + ## + # URL for this with a +prefix+ + + def http_url(prefix) + path = [prefix, @relative_name.tr('.', '_')] + + File.join(*path.compact) + '.html' + end + + def inspect # :nodoc: + "#<%s:0x%x %p modules: %p classes: %p>" % [ + self.class, object_id, + base_name, + @modules.map { |n,m| m }, + @classes.map { |n,c| c } + ] + end + + ## + # Time this file was last modified, if known + + def last_modified + @file_stat ? file_stat.mtime : nil + end + + ## + # Dumps this TopLevel for use by ri. See also #marshal_load + + def marshal_dump + [ + MARSHAL_VERSION, + @relative_name, + @parser, + parse(@comment), + ] + end + + ## + # Loads this TopLevel from +array+. + + def marshal_load array # :nodoc: + initialize array[1] + + @parser = array[2] + @comment = array[3] + + @file_stat = nil + end + + ## + # Returns the NormalClass "Object", creating it if not found. + # + # Records +self+ as a location in "Object". + + def object_class + @object_class ||= begin + oc = @store.find_class_named('Object') || add_class(RDoc::NormalClass, 'Object') + oc.record_location self + oc + end + end + + ## + # Base name of this file without the extension + + def page_name + basename = File.basename @relative_name + basename =~ /\.(rb|rdoc|txt|md)$/i + + $` || basename + end + + ## + # Path to this file for use with HTML generator output. + + def path + http_url @store.rdoc.generator.file_dir + end + + def pretty_print q # :nodoc: + q.group 2, "[#{self.class}: ", "]" do + q.text "base name: #{base_name.inspect}" + q.breakable + + items = @modules.map { |n,m| m } + items.concat @modules.map { |n,c| c } + q.seplist items do |mod| q.pp mod end + end + end + + ## + # Search record used by RDoc::Generator::JsonIndex + + def search_record + return unless @parser < RDoc::Parser::Text + + [ + page_name, + '', + page_name, + '', + path, + '', + snippet(@comment), + ] + end + + ## + # Is this TopLevel from a text file instead of a source code file? + + def text? + @parser and @parser.ancestors.include? RDoc::Parser::Text + end + + def to_s # :nodoc: + "file #{full_name}" + end + +end + |