class IRB::SLex::Node

———————————————————————-
class Node -
———————————————————————-

def create_subnode(chrs, preproc = nil, postproc = nil)

def create_subnode(chrs, preproc = nil, postproc = nil)
  if chrs.empty?
    if @postproc
      D_DETAIL.pp node
      raise "node already exists"
    else
      D_DEBUG.puts "change abstract node to real node."
      @preproc = preproc
      @postproc = postproc
    end
    return self
  end
  ch = chrs.shift
  if node = @Tree[ch]
    if chrs.empty?
      if node.postproc
        DebugLogger.pp node
        DebugLogger.pp self
        DebugLogger.pp ch
        DebugLogger.pp chrs
        raise "node already exists"
      else
        D_WARN.puts "change abstract node to real node"
        node.preproc = preproc
        node.postproc = postproc
      end
    else
      node.create_subnode(chrs, preproc, postproc)
    end
  else
    if chrs.empty?
      node = Node.new(preproc, postproc)
    else
      node = Node.new
      node.create_subnode(chrs, preproc, postproc)
    end
    @Tree[ch] = node
  end
  node
end

def initialize(preproc = nil, postproc = nil)

if postproc is non-nil, this node is a real node.
if postproc is nil, this node is an abstract node.
def initialize(preproc = nil, postproc = nil)
  @Tree = {}
  @preproc = preproc
  @postproc = postproc
end

def match(chrs, op = "")


able to be called arbitrary number of times.
io must have getc()/ungetc(); and ungetc() must be
character array
chrs: String
def match(chrs, op = "")
  D_DETAIL.print "match>: ", chrs, "op:", op, "\n"
  if chrs.empty?
    if @preproc.nil? || @preproc.call(op, chrs)
      DOUT.printf(D_DETAIL, "op1: %s\n", op)
      @postproc.call(op, chrs)
    else
      nil
    end
  else
    ch = chrs.shift
    if node = @Tree[ch]
      if ret = node.match(chrs, op+ch)
        return ret
      else
        chrs.unshift ch
        if @postproc and @preproc.nil? || @preproc.call(op, chrs)
          DOUT.printf(D_DETAIL, "op2: %s\n", op.inspect)
          ret = @postproc.call(op, chrs)
          return ret
        else
          return nil
        end
      end
    else
      chrs.unshift ch
      if @postproc and @preproc.nil? || @preproc.call(op, chrs)
        DOUT.printf(D_DETAIL, "op3: %s\n", op)
        @postproc.call(op, chrs)
        return ""
      else
        return nil
      end
    end
  end
end

def match_io(io, op = "")

def match_io(io, op = "")
  if op == ""
    ch = io.getc
    if ch == nil
      return nil
    end
  else
    ch = io.getc_of_rests
  end
  if ch.nil?
    if @preproc.nil? || @preproc.call(op, io)
      D_DETAIL.printf("op1: %s\n", op)
      @postproc.call(op, io)
    else
      nil
    end
  else
    if node = @Tree[ch]
      if ret = node.match_io(io, op+ch)
        ret
      else
        io.ungetc ch
        if @postproc and @preproc.nil? || @preproc.call(op, io)
          DOUT.exec_if{D_DETAIL.printf "op2: %s\n", op.inspect}
          @postproc.call(op, io)
        else
          nil
        end
      end
    else
      io.ungetc ch
      if @postproc and @preproc.nil? || @preproc.call(op, io)
        D_DETAIL.printf("op3: %s\n", op)
        @postproc.call(op, io)
      else
        nil
      end
    end
  end
end

def search(chrs, opt = nil)

def search(chrs, opt = nil)
  return self if chrs.empty?
  ch = chrs.shift
  if node = @Tree[ch]
    node.search(chrs, opt)
  else
    if opt
      chrs.unshift ch
      self.create_subnode(chrs)
    else
      raise "node nothing"
    end
  end
end