module MIKU::List

MIKUがリストとして扱えるようにするためのmix-in。 これをincludeするクラスは、car, cdr, setcar, setcdrを実装している必要がある。

Public Instance Methods

+(other) click to toggle source

#set_terminatorと同じだが、非破壊的。

# File core/miku/list.rb, line 35
def +(other)
  copycdr.set_terminator(other)
end
[](beg, en=nil) click to toggle source

beg 番目の要素を取得する。 範囲を超えていた場合nilを返す。 Rangeが渡されたら、その範囲を切り取って返す。 en が指定されたら、 beg .. en を返す。

# File core/miku/list.rb, line 16
def [](beg, en=nil)
  if not(en) and beg.is_a?(Integer)
    nth(beg)
  elsif en
    to_a[beg, en]
  else
    to_a[beg] end end
[]=(index, value) click to toggle source

index 番目の要素を value に置き換える。 index がRangeなら、その範囲を配列 value で置き換える。

# File core/miku/list.rb, line 26
def []=(index, value)
  if index.is_a?(Integer)
    nthcdr(index).setcar(value)
  elsif index.is_a?(Range)
    nthcdr(index.first).setcdr(value.to_cons.copycdr.set_terminator(nthcdr(index.last)))
  end
end
_unparse() click to toggle source
# File core/miku/list.rb, line 171
def _unparse
  result = ''
  result << MIKU.unparse(self.car)
  if(self.cdr == nil)
    result + ')'
  elsif(self.cdr.is_a? List)
    result + ' ' + self.cdr._unparse
  else
    result + ' . ' + MIKU.unparse(self.cdr) + ')'
  end
end
call_rubyfunc(fn, receiver, *args) click to toggle source
# File core/miku/list.rb, line 133
def call_rubyfunc(fn, receiver, *args)
  func = if receiver.respond_to?(fn) then receiver.method(fn)
         elsif Kernel.respond_to?(fn) then
           args.unshift(receiver)
           Kernel.method(fn) end
  if func
    begin
      block = nil
      count = if func.arity < 0 then -(func.arity)+1 else func.arity end
      if args.size > count
        atmp = args.dup
        block = atmp.pop
        if(block.respond_to? :call)
          args = atmp
        else
          block = nil end end
      func.call(*args, &block)
    rescue => e
      raise e end
  else
    raise NoMithodError.new(fn, self) end end
copycdr() click to toggle source
# File core/miku/list.rb, line 45
    def copycdr
      if cdr.is_a? List
        Cons.new(car, cdr.copycdr)
      else
        Cons.new(car, (cdr.dup rescue cdr)) end end

    def nth(n)
      result = nthcdr(n)
      if not result.respond_to?(:car)
        raise ExceptionDelegator.new("nthがリストではないもの(#{MIKU.unparse self}の#{n}番目)に対して使われました", TypeError)
      end
      result.car
    end

    def nthcdr(n)
      raise "cant comparable #{n.inspect} in #{self.inspect}" if not n.respond_to?(:<=)
      return self if(n <= 0)
      self.cdr.nthcdr(n-1)
    end

    def terminator
      if cdr.is_a? List
        cdr.terminator
      else
        cdr end end

    def terminator=(value)
      set_terminator(value)
      value end

    def set_terminator(value)
      if cdr.is_a? List
        cdr.set_terminator(value)
      else
        setcdr(value) end
      self end

    alias append set_terminator

    def to_cons
      if cdr.is_a? List
        MIKU::Cons.new(car, cdr.to_cons)
      else
        MIKU::Cons.new(car, cdr) end end

    def list_check(symtable, list)
      raise ArgumentError.new("#{node.inspect} の評価結果 #{list.inspect}の#{parse_caller(caller(2))[2]}を参照しました") if not list.is_a? List
      return list
    end

    def mapcarcdr(converter)
      Cons.new(*[car, cdr].map{ |node|
                 if(node.is_a?(List))
                   node.mapcarcdr(converter)
                 else
                   converter.call(node) end }) end

    # ツリーの葉をすべてruleにしたがって置換する。
    # ruleには、((検索するノード 置換するノード) ...)というリストを渡す
    def replace(rule)
      mapcarcdr(lambda{ |n|
                  r = rule.assoc(n)
                  if r.nil? then n else r[1] end }) end

    def miku_eval(symtable=SymbolTable.new)
      return nil if(empty?)
      result = nil
      begin
        operator = get_function(symtable)
        if operator.is_a? Primitive
          result = operator.call(symtable, *cdr.to_a)
        elsif operator.respond_to?(:macro_expand)
          result = miku(operator.macro_expand(*cdr.to_a), symtable)
        elsif operator.respond_to?(:call)
          result = operator.call(*evaluate_args(symtable))
        elsif operator.is_a? Symbol
          result = call_rubyfunc(operator, *evaluate_args(symtable))
        else
          raise NoMithodError.new(operator, self)
        end
      rescue ExceptionDelegator => e
        e.fire(self)
      end
      if result.is_a? List
        result.dup.extend(StaticCode).staticcode_copy_info(self)
      else
        result end end

    def call_rubyfunc(fn, receiver, *args)
      func = if receiver.respond_to?(fn) then receiver.method(fn)
             elsif Kernel.respond_to?(fn) then
               args.unshift(receiver)
               Kernel.method(fn) end
      if func
        begin
          block = nil
          count = if func.arity < 0 then -(func.arity)+1 else func.arity end
          if args.size > count
            atmp = args.dup
            block = atmp.pop
            if(block.respond_to? :call)
              args = atmp
            else
              block = nil end end
          func.call(*args, &block)
        rescue => e
          raise e end
      else
        raise NoMithodError.new(fn, self) end end

    def get_function(symtable)
      if car.is_a? Symbol
        symtable[car].cdr or symtable[car].car or car
      else
        miku_eval_another(symtable, car)
      end
    end

    def evaluate_args(scope)
      cdr.map{|node| miku(node, scope)} if cdr.is_a?(Enumerable)
    end

    def unparse
      '(' + _unparse
    end

    def _unparse
      result = ''
      result << MIKU.unparse(self.car)
      if(self.cdr == nil)
        result + ')'
      elsif(self.cdr.is_a? List)
        result + ' ' + self.cdr._unparse
      else
        result + ' . ' + MIKU.unparse(self.cdr) + ')'
      end
    end
  end

end
evaluate_args(scope) click to toggle source
# File core/miku/list.rb, line 163
def evaluate_args(scope)
  cdr.map{|node| miku(node, scope)} if cdr.is_a?(Enumerable)
end
get_function(symtable) click to toggle source
# File core/miku/list.rb, line 155
def get_function(symtable)
  if car.is_a? Symbol
    symtable[car].cdr or symtable[car].car or car
  else
    miku_eval_another(symtable, car)
  end
end
list_check(symtable, list) click to toggle source
# File core/miku/list.rb, line 90
def list_check(symtable, list)
  raise ArgumentError.new("#{node.inspect} の評価結果 #{list.inspect}の#{parse_caller(caller(2))[2]}を参照しました") if not list.is_a? List
  return list
end
mapcarcdr(converter) click to toggle source
# File core/miku/list.rb, line 95
def mapcarcdr(converter)
  Cons.new(*[car, cdr].map{ |node|
             if(node.is_a?(List))
               node.mapcarcdr(converter)
             else
               converter.call(node) end }) end
miku_eval(symtable=SymbolTable.new) click to toggle source
# File core/miku/list.rb, line 109
def miku_eval(symtable=SymbolTable.new)
  return nil if(empty?)
  result = nil
  begin
    operator = get_function(symtable)
    if operator.is_a? Primitive
      result = operator.call(symtable, *cdr.to_a)
    elsif operator.respond_to?(:macro_expand)
      result = miku(operator.macro_expand(*cdr.to_a), symtable)
    elsif operator.respond_to?(:call)
      result = operator.call(*evaluate_args(symtable))
    elsif operator.is_a? Symbol
      result = call_rubyfunc(operator, *evaluate_args(symtable))
    else
      raise NoMithodError.new(operator, self)
    end
  rescue ExceptionDelegator => e
    e.fire(self)
  end
  if result.is_a? List
    result.dup.extend(StaticCode).staticcode_copy_info(self)
  else
    result end end
nth(n) click to toggle source
# File core/miku/list.rb, line 51
def nth(n)
  result = nthcdr(n)
  if not result.respond_to?(:car)
    raise ExceptionDelegator.new("nthがリストではないもの(#{MIKU.unparse self}の#{n}番目)に対して使われました", TypeError)
  end
  result.car
end
nthcdr(n) click to toggle source
# File core/miku/list.rb, line 59
def nthcdr(n)
  raise "cant comparable #{n.inspect} in #{self.inspect}" if not n.respond_to?(:<=)
  return self if(n <= 0)
  self.cdr.nthcdr(n-1)
end
replace(rule) click to toggle source

ツリーの葉をすべてruleにしたがって置換する。 ruleには、((検索するノード 置換するノード) …)というリストを渡す

# File core/miku/list.rb, line 104
def replace(rule)
  mapcarcdr(lambda{ |n|
              r = rule.assoc(n)
              if r.nil? then n else r[1] end }) end
set_terminator(value) click to toggle source
# File core/miku/list.rb, line 75
def set_terminator(value)
  if cdr.is_a? List
    cdr.set_terminator(value)
  else
    setcdr(value) end
  self end
size() click to toggle source
# File core/miku/list.rb, line 39
def size
  if cdr.is_a? List
    1 + cdr.size
  else
    1 end end
terminator() click to toggle source
# File core/miku/list.rb, line 65
def terminator
  if cdr.is_a? List
    cdr.terminator
  else
    cdr end end
terminator=(value) click to toggle source
# File core/miku/list.rb, line 71
def terminator=(value)
  set_terminator(value)
  value end
to_cons() click to toggle source
# File core/miku/list.rb, line 84
def to_cons
  if cdr.is_a? List
    MIKU::Cons.new(car, cdr.to_cons)
  else
    MIKU::Cons.new(car, cdr) end end
unparse() click to toggle source
# File core/miku/list.rb, line 167
def unparse
  '(' + _unparse
end