Self-modifying esoteric language interpreter in Ruby I recently created Copy, an esoteric language, and wrote an implementation in Ruby.

The language has only 7 instructions:


copy &lt;a&gt; &lt;b&gt; &lt;c&gt; Copy the code block from a to b at c
remove &lt;a&gt; &lt;b&gt; Remove the code block from a to b
skip &lt;value&gt; Skip the next instruction if value is not 0
add &lt;var&gt; &lt;value&gt; Add value to var
negate &lt;var&gt; Negate var
print &lt;value&gt; Print value as an ASCII character
getch &lt;var&gt; Read a character and store it character code in var


All addresses are relative and values can be variables or signed integers,



require "io/console"

class Copy
    def initialize(code)
        @code = code.lines.map &amp;:chomp
        @len = @code.length*2
        @i = 0
        @vars = {}
    end

    def value(s)
        if s =~ /-?\d+/
            s.to_i
        else
            @vars[s] or 0
        end
    end

    def step
        while @code.length &gt; @len do
            @code.shift
            @i -= 1
        end
        line = @code[@i].split " "
        case line[0]
        when "copy"
            @code.insert(
                @i + value(line[3]),
                *@code.slice((@i + value(line[1]))..(@i + value(line[2])))
                )
        when "remove"
            @code.slice!((@i + value(line[1]))..(@i + value(line[2])))
        when "skip"
            if value(line[1]) != 0
                @i += 1
            end
        when "add"
            @vars[line[1]] = (@vars[line[1]] or 0) + value(line[2])
        when "negate"
            @vars[line[1]] *= -1
        when "print"
            STDOUT.write value(line[1]).chr
        when "getch"
            @vars[line[1]] = STDIN.getch.ord
        end
        @i += 1
    end

    def run
        while @i &lt; @code.length
            step
        end
    end
end

if __FILE__ == $0
    unless ARGV[0]
        puts "Copy interpreter in Ruby"
        puts "Usage: #{$0} &lt;file&gt;"
    end

    c = Copy.new File.read(ARGV[0])
    c.run
end


Truth machine (If the input is 0, print 0 and exit, if the input is 1, print 1 in an infinite loop):

getch a
add b a
add b -48
print a
skip b
skip 1
copy -4 0 1


I am not really good at Ruby, can someone review this?
I would suggest refactoring the switch. This would make scaling easier

   def remove_callback
     @code.slice!((@i + value(line[1]))..(@i + value(line[2])))
   end

   ...

   line = @code[@i].split " "
   self.send("#{line[0]}_callback")