Class: RpRb::DC

Inherits:
Object
  • Object
show all
Defined in:
lib/rprb.rb

Instance Method Summary collapse

Constructor Details

#initializeDC

Returns a new instance of DC.



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
# File 'lib/rprb.rb', line 36

def initialize
    @reader = Reader.new

    @stack = []

    @registers = {
        :eval => proc { |x| eval x },
        :read => proc { |x| read x },

        :p => proc { ||
            puts "___"
            puts @stack.collect_with_index { |entry, i| "%3d: %s" % [i, entry.inspect] }.reverse.join("\n")
            puts "---"
            :noval
        },

        :pick => proc { |n| @stack[n] },
        :del => proc { |n| @stack.slice!(n); :noval },
        :sto => proc { |val, sym| @registers[sym] = val; :noval },
        :rcl => proc { |sym| @registers[sym] },
        :if => proc { |den, elz, test| if test; den; else; elz; end },
        :len => proc { || @stack.length },

			:push => proc { |array, elem| array.push elem; array },

        :while => proc { |expr, cond| loop { eval(cond); break unless @stack.shift; eval(expr) }; :noval },
        :evaln => proc { |expr, n| n.times { eval(expr) }; :noval },
        :loop => proc { |expr, times| times.times { |i| @stack.unshift(i); eval(expr) }; :noval },
        :each => proc { |enumerable, expr| enumerable.each { |elem| @stack.unshift(elem); eval(expr) }; :noval },

        :array => proc { |length| @stack.slice!(0, length).reverse },

			:regs => proc { || @registers.keys },
    }


    [
        read('{ Array.new } :"[]" sto'),
        read('0 array :control sto'),
        read('{ false true 2 pick if 1 del } :not sto'),
        read('{ :control rcl swap unshift :control sto } :save sto'),
        read('{ :control rcl 0 slice! } :restore sto'),
        read('{ 1 pick 2 del } :swap sto'),
        read('{ 0 del } :drop sto'),
        read('{ 0 pick } :dup sto'),
        read('{ {drop} swap evaln } :dropn sto'),
        read('{ 2 dropn } :drop2 sto'),
        read('{ 2 dupn } :dup2 sto'),
        read('{ len dropn } :clr sto'),
        read('{ rcl eval } :exe sto'),
        read('{ swap rcl swap evaln } :exen sto'),
        read('{ 1 - } :dec sto'),
        read('{ 1 + } :inc sto'),
        read('{ -1 * } :neg sto'),
        read('{ 1.0 swap / } :inv sto'),
        read('{ restore dup save } :peek sto'),
        read('{ restore drop save } :poke sto'),
        read('{ save {peek 1 - pick} peek evaln restore drop } :dupn sto'),
        read('0 array :nop sto'),
        read('{ swap dup length save swap each restore array } :map sto'),
        read('{ File swap open save peek readlines restore close drop } :slurp sto'),
        read('{ slurp {chomp} map {read} map {eval} each } :load sto'),
        read('{ inc dup pick swap del } :take sto'),
        read('{ len {+} swap dec evaln } :sum sto'),
    ].each { |stream| eval(stream) }
end

Instance Method Details

#eval(tokens) ⇒ Object



117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/rprb.rb', line 117

def eval(tokens)
    #puts "Eval-ing #{tokens.inspect}"
    tokens.each { |token|
        #puts "processing token #{token.inspect}..."
        result = trythese(
         *[
            proc { execute(token.intern)                     },
            proc { parse_code(token)                         },
            proc { Kernel.eval(token)                        },
            proc { puts("Error, nothing left to do"); :noval },
          ]
        )

        unless result == :noval
            @stack.unshift result
        end
    }

    :noval
end

#execute(fn) ⇒ Object



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
# File 'lib/rprb.rb', line 146

def execute(fn)
    # check if /fn/ names a register
    if @registers.include? fn
        case @registers[fn]
        when Proc, Method
            values = @stack.slice!(0, @registers[fn].arity).reverse
            return @registers[fn].call(*values)
        else
            return eval(@registers[fn])
        end
    end

    # check if /fn/ is a valid function call for an item on the stack
    @stack.each_with_index { |src, arity|
        begin
            if fn == :call and (src.is_a?(Proc) or src.is_a?(Method)) and (src.arity == arity or src.arity == -1)
                values = @stack.slice!(0, arity + 1).reverse
                return values[0].call(*values[1..-1])
            elsif src.respond_to?(fn) and (src.method(fn).arity == arity or src.method(fn).arity == -1)
                values = @stack.slice!(0, arity + 1).reverse
                return values[0].send(fn, *values[1..-1])
            end
        rescue ArgumentsError
        end
    }

    # check if /fn/ is a valid method of Kernel or Math
    [Kernel, Math].each { |src|
        begin
            if src.respond_to? fn
                values = @stack.slice!(0, src.method(fn).arity).reverse
                return src.send(fn, *values)
            end
        rescue
        end
    }

    raise "Couldn't execute function on stack item, DC, Kernel, or Math"
end

#parse_code(stream) ⇒ Object



138
139
140
141
142
143
144
# File 'lib/rprb.rb', line 138

def parse_code(stream)
    if stream.is_a? Array
        stream
    else
        raise "#{stream.inspect} isn't code!"
    end
end

#read(val) ⇒ Object



107
108
109
# File 'lib/rprb.rb', line 107

def read(val)
    @reader.read without_comments(val)
end

#stackObject



103
104
105
# File 'lib/rprb.rb', line 103

def stack
    @stack.dup
end

#without_comments(string) ⇒ Object



111
112
113
114
115
# File 'lib/rprb.rb', line 111

def without_comments(string)
  string.lines.map do |line|
    line.gsub(/#.*$/, '')
  end.join('')
end