6
\$\begingroup\$

I recently created Copy, an esoteric language, and wrote an implementation in Ruby.

The language has only 7 instructions:

  • copy <a> <b> <c> Copy the code block from a to b at c
  • remove <a> <b> Remove the code block from a to b
  • skip <value> Skip the next instruction if value is not 0
  • add <var> <value> Add value to var
  • negate <var> Negate var
  • print <value> Print value as an ASCII character
  • getch <var> 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 &: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 > @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 < @code.length
            step
        end
    end
end

if __FILE__ == $0
    unless ARGV[0]
        puts "Copy interpreter in Ruby"
        puts "Usage: #{$0} <file>"
    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?

\$\endgroup\$
  • \$\begingroup\$ I personally would change step to self.step to increase readability. \$\endgroup\$ – Conor O'Brien Sep 25 '16 at 16:36
3
\$\begingroup\$

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")
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.