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
|
# -*- coding: utf-8 -*-
require_relative 'error'
module MIKU
class SymbolTable < Hash
INITIALIZE_FILE = File.expand_path(File.join(File.dirname(__FILE__), 'init.miku'))
# :caller-file "呼び出し元ファイル名"
# :caller-line 行
# :caller-function :関数名
def initialize(parent = nil, default = {})
if parent
@parent = parent
else
@parent = MIKU::SymbolTable.initialized_table end
if(SymbolTable.defaults.equal?(parent))
def self.ancestor
self end end
super(){ |this, key| @parent[key.to_sym] }
merge!(default) unless default.empty?
end
def ancestor
@parent.ancestor end
def []=(key, val)
if not(key.is_a?(Symbol)) then
raise ExceptionDelegator.new("#{key.inspect} に値 #{val.inspect} を代入しようとしました", TypeError) end
super(key, val) end
def bind(key, val, setfunc)
cons = self[key]
if cons
cons.method(setfunc).call(val)
else
self[key] = nil.method(setfunc).call(val) end end
def set(key, val)
if not(key.is_a?(Symbol)) then
raise ExceptionDelegator.new("#{key.inspect} に値 #{val.inspect} を代入しようとしました", TypeError) end
bind(key.to_sym, val, :setcar) end
def defun(key, val)
if not(key.is_a?(Symbol)) then
raise ExceptionDelegator.new("#{key.inspect} に関数 #{val.inspect} を代入しようとしました", TypeError) end
bind(key.to_sym, val, :setcdr) end
def miracle_binding(keys, values)
_miracle_binding(SymbolTable.new(self), keys, values) end
def _miracle_binding(symtable, keys, values)
if(keys.is_a? Enumerable and values.is_a? Enumerable)
key = keys.car
val = values.car
if key.is_a? List
if key[0] == :rest
symtable[key[1]] = Cons.new(values)
return symtable end
else
symtable[key] = Cons.new(val) end
_miracle_binding(symtable, keys.cdr, values.cdr) end
symtable end
def self.initialized_table
@@initialized_table ||= (@@initialized_table = MIKU::SymbolTable.new(SymbolTable.defaults)).run_init_script end
def self.defsform(fn=nil, *other)
return [] if fn == nil
[fn , Cons.new(nil, Primitive.new(fn))] + defsform(*other) end
def self.defun(fn=nil, *other)
return [] if fn == nil
[fn , Cons.new(nil, fn)] + defun(*other) end
def self.consts
Module.constants.map{ |c| [c.to_sym, Cons.new(eval(c.to_s))] }.inject([]){ |a, b| a + b } end
# Module.constants.map{ |c| [c.to_sym, Cons.new(eval(c))] }.inject([]){ |a, b| a + b } end
def self.defaults
@@defaults ||= __defaults end
def self.__defaults
default = Hash[*(defsform(:cons, :listp, :set, :function, :value, :quote, :eval, :list,
:if, :backquote, :macro, :require_runtime_library, :+, :-, :*, :/,
:<, :>, :<=, :>=, :eq, :eql, :equal) +
[:lambda , Cons.new(nil, Primitive.new(:negi)),
:def , Cons.new(nil, Primitive.new(:defun)),
:'macro-expand' , Cons.new(nil, Primitive.new(:macro_expand)),
:'macro-expand-all' , Cons.new(nil, Primitive.new(:macro_expand_all)),
:'to-ruby' , Cons.new(nil, Primitive.new(:to_ruby)),
:"=", Cons.new(nil, Primitive.new(:eq)),
:not, Cons.new(nil, Primitive.new(:_not)),
:true, Cons.new(true, nil),
:false, Cons.new(false, nil)
] + consts)].freeze
Hash.new{ |h, k|
if default[k]
h[k] = default[k]
elsif /^[A-Z][a-zA-Z0-9_]*/ =~ k.to_s and klass = eval(k.to_s)
h[k] = klass
end }
end
def run_init_script
miku_stream(File.open(INITIALIZE_FILE), self)
self end
end
end
|