File: symboltable.rb

package info (click to toggle)
mikutter 5.1.0%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 9,780 kB
  • sloc: ruby: 22,912; sh: 186; makefile: 21
file content (129 lines) | stat: -rw-r--r-- 3,616 bytes parent folder | download | duplicates (2)
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
# -*- coding: utf-8 -*-
require_relative 'error'

module MIKU
  class RootSymbolTable
    def self.generate
      @root_symbol_table ||= RootSymbolTable.new
    end

    def initialize
      @__cache__table = {}
    end

    def root?
      true
    end

    def [](key)
      @__cache__table[key] ||= table(key)
    end

    private

    def table(key)
      case key.to_sym
      when :cons, :listp, :set, :function, :value, :quote, :eval, :list,
           :if, :backquote, :macro, :require_runtime_library, :+, :-, :*, :/,
           :<, :>, :<=, :>=, :eq, :eql, :equal
        Cons.new(nil, Primitive.new(key))
      when :lambda
        Cons.new(nil, Primitive.new(:negi))
      when :def
        Cons.new(nil, Primitive.new(:defun))
      when :'macro-expand'
        Cons.new(nil, Primitive.new(:macro_expand))
      when :'macro-expand-all'
        Cons.new(nil, Primitive.new(:macro_expand_all))
      when :'to-ruby'
        Cons.new(nil, Primitive.new(:to_ruby))
      when :"="
        Cons.new(nil, Primitive.new(:eq))
      when :not
        Cons.new(nil, Primitive.new(:_not))
      when :true
        Cons.new(true, nil)
      when :false
        Cons.new(false, nil)
      when *Object.constants
        Cons.new(Object.const_get(key.to_s))
      end
    end
  end

  class SymbolTable < Hash

    INITIALIZE_FILE = File.expand_path(File.join(__dir__, 'init.miku'))

    # :caller-file "呼び出し元ファイル名"
    # :caller-line 行
    # :caller-function :関数名
    def initialize(parent = nil, default = {})
      if parent
        @parent = parent
      else
        @parent = MIKU::SymbolTable.initialized_table end
      super(){ |this, key| @parent[key.to_sym] }
      merge!(default) unless default.empty?
    end

    def root?
      false
    end

    # なんかわからんけどRootSymbolTableの一個手前を返すらしい
    def ancestor
      if @parent.root?
        self
      else
        @parent.ancestor
      end
    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(RootSymbolTable.generate)).run_init_script end

    def run_init_script
      miku_stream(File.open(INITIALIZE_FILE), self)
      self end

  end
end