devdaily home | apple | java | perl | unix | directory | blog

What this is

This file is included in the DevDaily.com "Ruby Source Code Warehouse" project. The intent of this project is to help you "Learn Ruby by Example" TM.

Other links

The source code

# Copyritght (c) 2002 TANIGUCHI Takaki
# This program is distributed under the GNU GPL 2 or later.

require 'strscan'
require 'uri/common'
require 'delegate'

# require 'obaq/htmlgen'

require 'aswiki/scanner'
require 'aswiki/node'
require 'aswiki/util'
require 'aswiki/plugin'
require "aswiki/i18n/#{$LANG}"

module AsWiki
  class Parser
#    include Obaq::HtmlGen
    include AsWiki::Util
    include AsWiki::I18N
    WORD  = [:SPACE, :OTHER, :WORD]
    TAG = [:ENDPERIOD, :INTERWIKINAME, :WIKINAME1, :WIKINAME2, :URI,:MOINHREF,
    :MOINHREFIMG]
    DECORATION = [:EM, :STRONG]
    ESCAPE = [:ESCAPE_BEGIN, :ESCAPE_END]
    TEXTLINE = WORD + TAG + [:EOL] + ESCAPE
    PLAINTEXT = TEXTLINE + DECORATION
    ELEMENT = PLAINTEXT + [:UL, :OL]
    D_TAG = {:EM => 'Em' ,  :STRONG => 'Strong'}

    def initialize(scanner, name='')
      @name = name
      @s = scanner
      @rawwikinames = []
      @plugin = AsWiki::Plugin.new(@name)

      @tocdata = []
      @tocnum  = 0

      @tocdata = [{:number => "##{@tocnum}", :text => '', 
	  :msg_edit => msg_edit,
	  :partialedit => cgiurl([['c', 'e'],
				   ['ebol',1],
				   ['eeol',0]], @name)}]
      @lastbol = 1
      
      @tree = parse
    end
    attr_reader :tree, :tocdata
    def wikinames
      @rawwikinames.collect{|n|
	expandwikiname(n,@name)
      }
    end

    private 
    def next_token
      @token = @s.next_token
    end
    def current_indent       # To handle indents of ul and ol at onece
      indent = 0
      indent = $1.size if @token[1] =~ /^(\s*)/

      ## Original
      ## indent = @token[1].size
      return indent
    end
    def parse
      @line = 1
      node = Node.new('Root')
      next_token
      while true
	case @token[0]
	when *PLAINTEXT
	  node << paragraph
	when :UL
	  node << simple_list('Ul')
	when :OL
	  node << simple_list('Ol')
	when :BLANK       
	  node << blank
	when :DL          
	  node << dl
	when :EOL         
	  eol  
	  node << "\n"
	when :HN_BEGIN    
	  node << hn
	when :HR          
	  node << Node.new('Hr')
	  next_token
	when :PLUGIN  
	  node << plugin
	when :PLUGIN_BEGIN
	  node << plugin_block
	when :PRE_BEGIN   
	  node << preblock
	when :TABLE_BEGIN 
	  node << table
	when :EOF         
	  break
	else 
	  node << syntax_error
	end
      end 
      return node
    end
    def blank
      next_token
      while true
	case  @token[0]
	when :BLANK
	  next_token
	when :EOL  
	  eol
	else 
	  break
	end
      end
      return "\n"
    end
    def hn
      level = @token[1].size
      lineno = @line
      node = Node.new("H#{level}")
      next_token
      ret = textline
      if level == 2
	@tocnum = @tocnum + 1
	@tocdata[-1][:partialedit] = cgiurl([['c', 'e'],
                                             ['ebol',@lastbol],
                                             ['eeol',lineno-1]],@name)
	@lastbol = lineno
	@tocdata << {:number => "##{@tocnum}", :text => ret,
	  :msg_edit => msg_edit,
	  :partialedit => cgiurl([['c', 'e'],['ebol',@lastbol]],
                                 @name)
	}
	node << {:number => @tocnum, :text=> ret, }
      else
	node << {:number => nil, :text=> ret}
      end
      return node
    end
    def plugin_block
      block = [] << (@token[1]+"\n")
      block_b = @line
      if :EOL == next_token[0] then eol else node << syntax_error end
      block += textblock(:PLUGIN_END)
      while true
	case @token[0] 
	when :PLUGIN_END 
	  block << @token[1] 
	  next_token
	when :EOL 
	  eol 
	  break
	when :EOF
	  break
	else node << syntax_error
	end
      end
      block_e = @line 
      return @plugin.onview(block, block_b, block_e)
    end
    def plugin
      node = @token[1]
      next_token
      return @plugin.onview(node.to_a, @line, 0)
    end

    def dl
      node = Node.new('Dl')
      while true
	next_token
	node << { :title => textline,  :doc => element}
	case @token[0]
	when :DL 
	  next
	else
	  break
	end
      end
      return node
    end
    def simple_list(kind = 'Ol') # kind = 'Ol' or 'Ul'
      node = Node.new(kind)
      indent = current_indent
      next_token
      node << catch(:simple_list_end) do
	while true
	  case @token[0]
	  when *ELEMENT
	    node << element(indent)
	  else
	    break
	  end
	end
      end
      return node
    end
    def table
      node = Node.new('Table')
      while true
	case @token[0]
	when :TABLE_BEGIN
	  next_token
	  node << table_tr
	when :EOL
	  eol
	when :EOF
	  break
	else 
	  break
	end
      end
      return node
    end
    def table_tr
      col = []
      while true
	col << plaintext
	case @token[0]
	when :TABLE_END
	  eol
	  break  # XXX
	when :TABLE
	  next_token
	  next
	else 
	  break
	end
      end
      return {:col => col}
    end
    def paragraph
      node = Node.new('Paragraph')
      node << plaintext
      return node
    end
    def plaintext
      node = Node.new('Plaintext')
      while true
	case @token[0]
	when *TEXTLINE
	  node << textline
	when :STRONG
	  node << decorate(:STRONG)
	when :EM
	  node << decorate(:EM)
	else
	  break
	end
      end
      return node
    end
    def element(indent=0)
      node = Node.new('Element')
      while true
	case @token[0]
	when *PLAINTEXT
	  node << plaintext
	when :UL
          cur_indent = current_indent
	  if indent == cur_indent
	    next_token
	    break
	  elsif indent < cur_indent
	    node << simple_list('Ul')
	  elsif indent > cur_indent
	    throw :simple_list_end, node
	  else
	    raise RangeError
	  end
	when :OL          
          cur_indent = current_indent
	  if indent == cur_indent
	    next_token
	    break
	  elsif indent < cur_indent
	    node << simple_list('Ol')
	  elsif indent > cur_indent
	    throw :simple_list_end, node
	  else
	    raise RangeError
	  end
	else
	  break
	end
      end
      return node
    end
    def decorate(tag)
      next_token
      node = Node.new(D_TAG[tag])
      node  << textline
      if @token[0] == tag 
	next_token
      else                
	node << syntax_error
      end
      return node
    end

    def textline
      node = Node.new('Textline')
      while true
	case @token[0]
	when :ESCAPE_BEGIN
	  next_token
	  ret  = textblock(:ESCAPE_END)
	  node << ret
	when :ESCAPE_END
	  node << @token[1]
	when :OTHER, :SPACE, :WORD
	  node << @token[1]
	when :WIKINAME1,:INTERWIKINAME
	  @rawwikinames << @token[1]
	  # node << wikilink(@token[1], @name) # XXX
	  node << wikilink(expandwikiname(@token[1], @name))
	when :WIKINAME2
	  name = @token[1][2..-3]
	  @rawwikinames << name 
	  # node << wikilink(name, @name) # XXX
	  node << wikilink(expandwikiname(name, @name))
	when :URI
	  tn = Node.new('Url')
	  tn << {:url=>@token[1],:text=>@token[1]}
	  node << tn
	when :MOINHREFIMG
	  tn = Node.new('MoinhrefImg')
	  urlt, key = @token[1][1..-2].split(/\s+/, 2)
	  url = Amrita::Sanitizer::sanitize_url(urlt[4..-1], {'http' => true, 'https' => true})
 	  tn << {:url => url, :alt => key}
	  node << tn
	when :MOINHREF
	  allowedscheme = {'http' => true, 'https' => true, 'file' => true, 
	    'news' => true, 'ftp' => true, 'mailto' => true }
	  tn = Node.new('Moinhref')
	  url, key = @token[1][1..-2].split(/\s+/, 2)
	  url = Amrita::Sanitizer::sanitize_url(url,allowedscheme)

	  tn << {:url => url, :text => key }
	  node << tn
	when :ENDPERIOD
	  node << Node.new('Br')
	when :EOL
	  node << "\n"
	  eol
	  break
	else
	  break
	end
	next_token
      end
      return node
    end
    def textblock(endtag)
      node = []
      line = ""
      while true
	case @token[0]
	when :EOF   
	  break
	when :EOL   
	  line << "\n" 
	  node << line 
	  line = ""
	  eol 
	when endtag 
	  if not line.empty?
	    node << line
	  end
	  break
	else line << @token[1] 
	  next_token
	end
      end
      return node
    end
    def preblock
      next_token
      ret = Amrita::e(:pre, :class=>"code") { Amrita::CompactSpace.new(false) { textblock(:PRE_END).join  } } # XXX use template ???
      next_token
      return ret 
    end
    def eol
      @line +=1
      next_token
      return 
    end
    def syntax_error
      s = "(Syntax error at line #{@line}. ; #{@token.inspect})\n" 
	next_token 
      return s
    end
  end
end




Copyright 1998-2008 Alvin Alexander
All Rights Reserved.
 
devdaily.com is based in louisville, kentucky, and this web site is hosted by godaddy.com