1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
|
# -*- coding:utf-8 -*-
require_relative 'node'
require_relative 'primitive'
module MIKU
# MIKUがリストとして扱えるようにするためのmix-in。
# これをincludeするクラスは、car, cdr, setcar, setcdrを実装している必要がある。
module List
include Node
include Enumerable
# _beg_ 番目の要素を取得する。
# 範囲を超えていた場合nilを返す。
# Rangeが渡されたら、その範囲を切り取って返す。
# _en_ が指定されたら、 _beg_ .. _en_ を返す。
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_ に置き換える。
# _index_ がRangeなら、その範囲を配列 _value_ で置き換える。
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
# set_terminatorと同じだが、非破壊的。
def +(other)
copycdr.set_terminator(other)
end
def size
if cdr.is_a? List
1 + cdr.size
else
1 end end
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)
elsif operator.respond_to?(:macro_expand)
result = miku(operator.macro_expand(*cdr), 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
require_relative 'cons'
require_relative 'array'
|