This is my code that interprets my own golfing and esoteric language, Fuzzy-Octo-Guacamole.
It has 2 stacks to store information in, and various operations can be performed on each stack, or both at once.
This is also my first real project using classes, so any advice on how I did would be much appreciated.
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
"""
^ push
ಠ or . shift
_ pop
: get
o peek
; print
number push number
{ } if
( ) loop
@ exit
+ increment
- decrement
? increment global counter
! set global counter to top of stack
' ' no-op
c clear active stack
" string literal
' string literal
U push 0
N push None
K print _UNK
I interleave
🐐 print goat ascii art
g print goat ascii art
= ala ruby rocketship op
< start a list with spaces as separators
s move the top item of the active stack to the inactive one
i invert the ToS
e throw error
r clear the global counter and push it to the stack
a add the top 2 items of the active stack
R string replacement
C copy the active stack to the inactive
j string.join
z reverse the ToS, i.e. 'asd' -> 'dsa'
* multiply the top 2 items on the active stack
"""
import re
import sys
import string
from stack import Stack
class FOG(object):
# Storage
commands = {
"^": "_input",# ^_^
"ಠ": "_swap_stacks", # ಠ_ಠ
".": "_swap_stacks", # ._.
"_": "_pop",
":": "_print_all",# :_:
"o": "_peek", # o_O
";": "_print_register",# ;_;
"{": "_skip",# {_{
"@": "_exit", # @_@
"+": "_increment",# +_+
"-": "_decrement",# -_-
"?": "_increment_register",# ?_?
"c": "_clear",# c_c
'"': "_string_lit",# "_"
"(": "_infinite_loop",# (_(
"[": "_for_loop",# [_[
"!": "_set_register",# !_!
"U": "_zero",# U_U
"N": "_none",# N_N
"K": "_unk",# K_K
"I": "_interleave",# I_I
")": "_noop",# )_)
"}": "_noop",# }_}
"]": "_noop",# ]_]
" ": "_noop",
"'": "_string_lit2",# '_'
">": "_noop",# >_>
"🐐": "_goat",# 🐐 _🐐
"g": "_goat",# g_g
"=": "_rocket",# =_=
"<": "_list",# <_<
"s": "_switch",# s_s
"i": "_invert",# i_i
"e": "_error", # e_e
"r": "_clear_register",# r_r
"a": "_add",# a_a
"R": "_replace",# R_R
"C": "_copy",# C_C
"j": "_join",# j_j
"z": "_reverse",# z_z
"*": "_mult",# *_*
}
# Main
def __init__(self):
self.reg = 0
self.ccount = 0
self.idx = 0
self.temp = None
self.active = Stack()
self.inactive = Stack()
def _uncomment(self, program):
program = program.split('\n')
p = []
for i in program:
p.append(re.sub('#.+','',i))
return ''.join(p)
def execute(self, program, idx=0):
self.idx = idx
program = self._encode(program)
program = self._uncomment(program)
for char in program:
self.idx += 1
if self.ccount:
self.ccount -= 1
continue
cmd = FOG.commands.get(char, "_push")
if cmd == "_push":
getattr(self, cmd)(char)
elif cmd in ["_for_loop",'_infinite_loop','_list','_string_lit','_skip', '_string_lit2']:
getattr(self, cmd)(program)
else:
getattr(self, cmd)()
if not any([i in program for i in [';',':', 'K']]):
print self.active.peek()
# Helpers
def _encode(self, val):
return val.replace(u"ಠ", ".").replace(u'🐐','g')
def _decode(self, val):
return val.replace(".", u"ಠ").replace('g',u'🐐')
def _simplify(self, val):
if all(e in unicode(string.digits) for e in unicode(val)) and type(val) != list and val:
return int(val)
elif type(val) == str and re.findall("\d?\.\d+", val):
if re.findall("\d?\.\d+", val)[0] == val:
return float(val)
else:
return unicode(val)
# Operators
def _noop(self):
pass
def _input(self):
y = [self._simplify(i) for i in raw_input().split(' ')]
for i in y:
self.active.push(i)
def _swap_stacks(self):
self.active, self.inactive = self.inactive, self.active
def _pop(self):
self.temp = str(self.active.pop())
def _print_all(self):
print self.active.get()
def _peek(self):
self.temp = self.active.peek()
def _print_register(self):
if self.temp:
print self._simplify(self.temp)
elif self.temp == 0:
print self._simplify(self.temp)
else:
print self.temp
def _skip(self, program):
if self.active.peek():
self.ccount += program.index("}", self.idx) - self.idx
def _exit(self):
sys.exit()
def _increment(self):
x = self._simplify(self.active.pop())
if isinstance(x, (int, float)):
self.active.push(x + 1)
def _decrement(self):
x = self._simplify(self.active.pop())
if isinstance(x, (int, float)):
self.active.push(x - 1)
def _increment_register(self):
self.reg += 1
def _clear(self):
self.active.clear()
def _string_lit(self, program):
y = program[self.idx:program.index('"', self.idx)]
self.active.push(y)
self.ccount += program.index('"', self.idx) - self.idx + 1
def _string_lit2(self, program):
y = program[self.idx:program.index("'", self.idx)]
self.active.push(y)
self.ccount += program.index("'", self.idx) - self.idx + 1
def _list(self, program):
y = [self._simplify(i) for i in program[self.idx:program.index(">", self.idx)].split(' ')]
self.active.push(y)
self.ccount += program.index(">", self.idx) - self.idx
def _infinite_loop(self, program):
p = program[self.idx:program.index(")", self.idx)]
while True:
self.execute(p)
def _for_loop(self, program):
x = program.index(']',self.idx)+1
p = program[self.idx:x]
while self.reg > 1:
self.execute(p, 0)
self.reg-=1
def _set_register(self):
x = self._simplify(self.active.peek())
if isinstance(x, (int, float)):
self.reg = x
else: self.reg = len(x)
def _clear_register(self):
self.active.push(self.reg)
self.reg = 0
def _zero(self):
self.active.push(0)
def _none(self):
self.active.push(None)
def _unk(self):
print "_UNK"
def _interleave(self):
self.inactive = self.active.weave(self.inactive)
def _goat(self):
print '''
___.
// \\\\
(( ''
\\\\__,
/6 (%)\\,
(__/:";,;\\--____----_
\a;; :';,:';`;,';,;';`,`_
;:,;;';';,;':,';';,-Y\\
;,;,;';';,;':;';'; Z/
/ ;,';';,;';,;';;'
/ / |';/~~~~~\\';;'
( K | | || |
\\_\\ | | || |
\\Z | | || |
L_| LL_|
LW/ LLW/'''
def _push(self, char):
self.active.push(self._simplify(char))
def _rocket(self):
x = self.active.peek()
y = self.inactive.peek()
if x < y or type(x) != type(y):
self.active.push(self._simplify('-1'))
elif x > y:
self.active.push(self._simplify('1'))
else:
self.active.push(self._simplify('0'))
def _switch(self):
self.inactive.push(self.active.pop())
def _reverse(self):
x = self.active.pop()
if type(x) == str or type(x) == unicode or type(x) == list:
self.active.push(x[::-1])
else:
self.active.push(x)
def _invert(self):
x = self.active.pop()
if type(x) == int:
self.active.push(int(not x))
elif type(x) == list:
if x:
self.active.push([])
else:
self.active.push([1])
elif type(x) == str or type(x) == unicode:
if x:
self.active.push('')
else:
self.active.push('avocad')
elif type(x) == bool:
self.active.push(not x)
else:
self.active.push(not x)
def _error(self):
raise ValueError("This is an error, in case you can't tell.")
def _add(self):
x = self.active.pop()
y = self.active.pop()
if type(x) == type(y):
self.active.push(x + y)
else:
self.active.push(y)
self.active.push(x)
def _copy(self):
self.inactive = Stack(self.active)
def _replace(self):
self.active.push(self._simplify(str().replace(str(self.inactive.pop()), str(self.inactive.pop()))))
def _join(self):
for i in self.active:
i = str(i)
x = unicode(''.join(self.active))
self.active.clear()
self.active.push(x)
def _mult(self):
x = self.active.pop()
y = self.active.pop()
if type(x) == str and type(y) == str:
self.active.push(y)
self.active.push(x)
else:
self.active.push(x*y)
# Debug
lang_inst = FOG()
#^!["a"'b'C.ss.jo;]
code = u"""^i_;"""
code = lang_inst._decode(code)
lang_inst.execute(lang_inst._encode(code))