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
|
# -*- coding: utf-8 -*-
require_relative 'atom'
require_relative 'error'
require_relative 'macro'
require_relative 'to_ruby'
module MIKU
class Primitive
include Atom
include ToRuby
def initialize(func)
@func = func.to_sym
end
def call(*args)
send(@func, *args)
end
def self.injecting_method(name, method = nil)
method = name unless method
define_method(name){ |symtable, *objects|
unless objects.empty?
first, *rest = *objects
rest.inject(eval(symtable, first)){|a, b|
a.__send__(method, eval(symtable, b)) } end } end
def self.consing_method(name, method = nil)
method = name unless method
define_method(name){ |symtable, *objects|
unless objects.empty?
objects.map{ |x| eval(symtable, x) }.enum_for(:each_cons, 2).all?{ |a|
a[0].__send__(method, a[1]) } end } end
injecting_method(:+)
injecting_method(:-)
injecting_method(:*)
injecting_method(:/)
consing_method(:<)
consing_method(:>)
consing_method(:<=)
consing_method(:>=)
consing_method(:eq, :equal?)
consing_method(:eql, :==)
consing_method(:equal, :===)
def backquote(symtable, val)
result = []
val.each{|n|
if not n.is_a?(List) then
result << n
elsif n.car == :comma then
result << eval(symtable, n[1])
elsif n.car == :comma_at then
list = eval(symtable, n[1])
raise ExceptionDelegator.new(',@がリスト以外に対して適用されました', ArgumentError) if not list.is_a?(List)
result.concat(list.to_a) if list
else
result << backquote(symtable, n)
end
}
result
end
def cons(symtable, head, tail)
Cons.new(eval(symtable, head), eval(symtable, tail))
end
def eval(symtable, node)
miku_eval_another(symtable, node)
end
def _not(symtable, sexp)
not eval(symtable, sexp) end
def if(symtable, condition, true_case, false_case = nil)
if(eval(symtable, condition)) then
eval(symtable, true_case)
else
eval(symtable, false_case)
end
end
def list(symtable, *args)
args.map{|n| eval(symtable, n) }.to_cons
end
def listp(symtable, val)
eval(symtable, val).is_a?(List)
end
def quote(symtable, val)
val
end
def set(symtable, key, val, *args)
raise ExceptionDelegator.new('setに与える引数は偶数個にして下さい', ArgumentError) if args.size == 1
key = eval(symtable, key)
val = eval(symtable, val)
symtable.set(key, val)
return val if args.empty?
set(symtable, *args)
end
def defun(symtable, key, val, *args)
raise ExceptionDelegator.new('defunに与える引数は偶数個にして下さい', ArgumentError) if args.size == 1
key = eval(symtable, key)
val = eval(symtable, val)
symtable.defun(key, val)
return val if args.empty?
defun(symtable, *args)
end
def function(symtable, symbol)
if symbol.is_a? Symbol
symtable[symbol].cdr
else
symbol end end
def macro(symtable, alist, *body)
Macro.new(alist, body)
end
def macro_expand_all(symtable, sexp)
macro_expand_all_ne(symtable, eval(symtable, sexp))
end
def macro_expand_all_ne(symtable, sexp)
if sexp.is_a?(List)
expanded = macro_expand_ne(symtable, sexp)
case expanded
in [Symbol => macro, *] if symtable[macro].cdr.is_a?(Macro)
macro_expand_all_ne(symtable, expanded)
in List
expanded.map(&method(:macro_expand_all_ne).curry.(symtable))
else
expanded
end
else
sexp
end
end
def macro_expand_ne(symtable, sexp)
if sexp.is_a? List
macro = if(sexp.car.is_a? Symbol)
symtable[sexp.car].cdr
else
eval(symtable, sexp.car) end
if macro.is_a?(Macro)
macro.macro_expand(*sexp.cdr)
else
sexp end
else
sexp end end
def to_ruby(symtable, sexp)
MIKU::ToRuby.to_ruby(macro_expand_all(symtable, sexp))
end
def to_ruby_ne(symtable, sexp)
MIKU::ToRuby.to_ruby(macro_expand_all_ne(symtable, sexp))
end
def macro_expand(symtable, sexp)
macro_expand_ne(symtable, eval(symtable, sexp))
end
def negi(parenttable, alist, *body)
# body = body.map{ |node| macro_expand(parenttable, node) }
lambda{ |*args|
symtable = parenttable.miracle_binding(alist, args)
body.inject(nil){ |last, operator|
eval(symtable, operator) } } end
def require_runtime_library(symtable, filename)
require eval(symtable, filename)
end
end
end
|