class RpRb::DC

Public Class Methods

new() click to toggle source
# 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

Public Instance Methods

eval(tokens) click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# File lib/rprb.rb, line 107
def read(val)
    @reader.read without_comments(val)
end
stack() click to toggle source
# File lib/rprb.rb, line 103
def stack
    @stack.dup
end
without_comments(string) click to toggle source
# File lib/rprb.rb, line 111
def without_comments(string)
  string.lines.map do |line|
    line.gsub(/#.*$/, '')
  end.join('')
end