Skip to content

Instantly share code, notes, and snippets.

@dorentus
Created March 6, 2014 06:51
Show Gist options
  • Save dorentus/9383791 to your computer and use it in GitHub Desktop.
Save dorentus/9383791 to your computer and use it in GitHub Desktop.
interpret = (code) ->
class Machine
constructor: -> @stack = []
push: (v) -> @stack.push(v)
pop: -> @stack.pop()
top: -> @stack[@stack.length - 1]
add: ->
a = @stack.pop()
b = @stack.pop()
@stack.push(b + a)
sub: ->
a = @stack.pop()
b = @stack.pop()
@stack.push(b - a)
mul: ->
a = @stack.pop()
b = @stack.pop()
@stack.push(b * a)
div: ->
a = @stack.pop()
b = @stack.pop()
@stack.push(if a == 0 then 0 else parseInt(Math.floor(b / a), 10))
mod: ->
a = @stack.pop()
b = @stack.pop()
@stack.push(if a == 0 then 0 else b % a)
nt: -> @stack.push(if @stack.pop() == 0 then 1 else 0)
gt: ->
a = @stack.pop()
b = @stack.pop()
@stack.push(if b > a then 1 else 0)
dup: -> @stack.push(this.top() or 0)
swp: ->
a = @stack.pop()
b = @stack.pop() or 0
@stack.push(a)
@stack.push(b)
class Playfield
DIRECTIONS =
R: [1, 0]
L: [-1, 0]
U: [0, -1]
D: [0, 1]
constructor: (code) ->
@program = code.split("\n").map (s) -> s.split('')
@direction = DIRECTIONS['R']
@position = { x: -1, y: 0 }
@token_at = (x, y) -> @program[y][x]
@token_set = (x, y, v) -> @program[y][x] = v
@current_token = -> @token_at(@position.x, @position.y)
@advance = -> @position.x += @direction[0]; @position.y += @direction[1]
@is_numeric = (n) -> n.toString() == parseInt(n, 10).toString()
@turn = (d) -> @direction = DIRECTIONS[d]
@turn_random = ->
r = Math.round(Math.random() * 100) % Object.keys(DIRECTIONS).length
@turn(Object.keys(DIRECTIONS)[r])
turn_left: -> @turn('L')
turn_right: -> @turn('R')
turn_up: -> @turn('U')
turn_down: -> @turn('D')
put_char: (x, y, v) -> @token_set(x, y, String.fromCharCode(v))
get_char: (x, y) -> @token_at(x, y)
next: ->
@advance()
if /\d/.test @current_token()
return { instruction: 'imm', value: parseInt(@current_token(), 10) }
switch @current_token()
when undefined then return undefined
when '@' then return undefined
when '>' then this.turn_right(); return this.next()
when '<' then this.turn_left(); return this.next()
when '^' then this.turn_up(); return this.next()
when 'v' then this.turn_down(); return this.next()
when '?' then @turn_random(); return this.next()
when '#' then @advance(); return this.next()
when ' ' then return { instruction: 'noop' }
when '"'
@advance()
char_stack = []
loop
break if @current_token() == '"'
char_stack.push @current_token()
@advance()
return { instruction: 'str', value: char_stack }
else
return { instruction: @current_token() }
class OutputStream
constructor: -> @buffer = []
put: (c) -> @buffer.push(c)
toString: -> @buffer.join('')
machine = new Machine
playfield = new Playfield(code)
output_stream = new OutputStream
loop
ins = playfield.next()
break if ins == undefined
switch ins.instruction
when 'imm' then machine.push(ins.value)
when 'str' then ins.value.forEach (c) -> machine.push(c.charCodeAt(0))
when '+' then machine.add()
when '-' then machine.sub()
when '*' then machine.mul()
when '/' then machine.div()
when '%' then machine.mod()
when '!' then machine.nt()
when '`' then machine.gt()
when ':' then machine.dup()
when '\\' then machine.swp()
when '$' then machine.pop()
when '_'
if machine.pop() == 0
playfield.turn_right()
else
playfield.turn_left()
when '|'
if machine.pop() == 0
playfield.turn_down()
else
playfield.turn_up()
when '.' then output_stream.put(machine.pop().toString())
when ',' then output_stream.put(String.fromCharCode(machine.pop()))
when 'p'
y = machine.pop()
x = machine.pop()
v = machine.pop()
playfield.put_char(x, y, v)
when 'g'
y = machine.pop()
x = machine.pop()
v = playfield.get_char(x, y).charCodeAt(0)
machine.push(v)
else
# no op
output_stream.toString()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment