/path/refimpl
Jump to navigation
Jump to search
- Note: there may be errors in the reference implementation. It's still young.
#!/bin/python3
import os.path as op, sys
errstr = '''/path error in block {bidx}:
/{block}/
{pad}^
{msg}
'''
subs = {
'\\':'/', 'P':'^', 'M':'\'', 'o':'`', 'D':'=', 'u':':', 'L':'#', 'O':'<',
'I':'>', 'a':'+', 'R':'-', 't':'*', 'm':'%', 'n':'_', 'A':'&', 'R':'|',
'N':'!'}
def subst(s):
for subst in subs: s = s.replace(subst, subs[subst])
return s
class SlashPathError(Exception): pass
class SlashPathNotEnoughInStack(SlashPathError): pass
class SlashPathDivideByZero(SlashPathError): pass
class SlashPathNegativeNumberOfItems(SlashPathError): pass
def dump(s):
sys.stdout.write('Stack stack: [\n')
for i, st in enumerate(reversed(s)):
sys.stdout.write(f' Stack {i}: [')
for x in reversed(st):
sys.stdout.write(f'\n {x}')
sys.stdout.write('\n ]\n')
sys.stdout.write(']\n')
def slashpath(filePath, dumpOnError = 0):
try:
bidx = 0
cidx = 0
try: f = open(filePath, 'r')
except: pass
else:
l = f.readlines()[-1].strip()
f.close()
if l.isdigit(): bidx = int(l)
filePath = subst(filePath)
blocks = [x for x in filePath.split('/') if x]
stackstack = [[]]
inputbuf = ''
while bidx < len(blocks):
while cidx < len(blocks[bidx]):
c = blocks[bidx][cidx]
# If there's not enough stuff in the stack
if c in 'kx:<j_!' and len(stackstack[-1]) < 1:
raise SlashPathNotEnoughInStack(c, 1)
if c in 'bB+-*d%&|qlg' and len(stackstack[-1]) < 2:
raise SlashPathNotEnoughInStack(c, 2)
if c == 'v':
stackstack.append([])
elif c == 'k':
n = stackstack[-1].pop()
if n < 0:
raise SlashPathNegativeNumberOfItems(c, n)
if len(stackstack[-1]) < n:
raise SlashPathNotEnoughInStack(c, n)
stackstack.append(stackstack[-1][-n:])
stackstack[-2] = stackstack[-2][:-n or None]
elif c in '^\'`':
if c == '^':
stackstack.pop()
elif c == '\'':
stackstack[-2].extend(stackstack.pop())
elif c == '`':
sys.stdout.write(' '.join(str(x) for x in stackstack.pop()))
if len(stackstack) == 0: stackstack.append([])
elif c == '=':
stackstack.append(stackstack[-1].copy())
elif c == 'S':
if len(stackstack) > 1:
stackstack.append(stackstack.pop(-2))
elif c == 'C':
stackstack.clear()
stackstack.append([])
elif c == 'x':
stackstack[-1].pop()
elif c == ':':
stackstack[-1].append(stackstack[-1][-1])
elif c == 's':
if len(stackstack[-1]) > 1:
stackstack[-1].append(stackstack[-1].pop(-2))
elif c == 'r':
stackstack[-1].reverse()
elif c == 'c':
stackstack[-1].clear()
elif '0' <= c <= '9':
stackstack[-1].append(int(c))
elif c == '#':
stackstack[-1].append(len(stackstack[-1]))
elif c == '<':
if 0 <= stackstack[-1][-1] < 0x110000:
sys.stdout.write(chr(stackstack[-1].pop()))
elif c == '>':
ch = sys.stdin.read(1)
stackstack[-1].append(ord(ch) if len(ch) else -1) # EOF
elif c == 'j':
bidx = max(0, min(bidx + stackstack[-1].pop(), len(blocks)-1))
cidx = -1
elif c == 'b':
n = stackstack[-1].pop()
if stackstack[-1].pop():
bidx = max(0, min(bidx + n, len(blocks)-1))
cidx = -1
elif c == 'B':
n = stackstack[-1].pop()
if not stackstack[-1].pop():
bidx = max(0, min(bidx + n, len(blocks)-1))
cidx = -1
elif c in '+-*d%&|qlg':
a = stackstack[-1].pop()
b = stackstack[-1].pop()
if c == '+':
stackstack[-1].append(b + a)
elif c == '-':
stackstack[-1].append(b - a)
elif c == '*':
stackstack[-1].append(b * a)
elif c == 'd':
if a == 0: raise SlashPathDivideByZero((c, b, a))
stackstack[-1].append(b // a)
elif c == '%':
if a == 0: raise SlashPathDivideByZero((c, b, a))
stackstack[-1].append(b % a)
elif c == '&':
stackstack[-1].append(b & a)
elif c == '|':
stackstack[-1].append(b | a)
elif c == 'q':
stackstack[-1].append(1 if b == a else 0)
elif c == 'l':
stackstack[-1].append(1 if b < a else 0)
elif c == 'g':
stackstack[-1].append(1 if b > a else 0)
elif c == '_':
stackstack[-1][-1] *= -1
elif c == '!':
stackstack[-1][-1] = ~stackstack[-1][-1]
else:
stackstack[-1].append(ord(c))
cidx += 1
# print(c, '->', stackstack)
cidx = 0
bidx += 1
return
except SlashPathError as e:
# Format a nice error message
# Dump stack stack and stack
if dumpOnError:
sys.stdout.write('\n')
sys.stdout.write('Memory dump\n')
sys.stdout.write('"""""""""""\n')
dump(stackstack)
sys.stdout.write('\n')
# Where to cut the block
l = len(blocks[bidx])
if l < 78 or cidx < 37: i1, i2, i3 = 0, min(77, l), cidx
elif cidx >= l - 37: i1, i2, i3 = l - 77, l, cidx - l - 77
else: i1, i2, i3 = cidx - 37, cidx + 38, 37
if type(e) is SlashPathDivideByZero:
msg = 'Division by zero'
elif type(e) is SlashPathNotEnoughInStack:
if len(e.args) < 2: msg = 'Not enough elements in stack'
else: msg = f'Not enough elements in stack, need {e.args[1]}'
elif type(e) is SlashPathNegativeNumberOfItems:
if len(e.args) < 2: msg = 'Can\'t count a negative number of items'
else: msg = f'Can\'t count a negative number of items ({e.args[1]})'
else:
msg = 'Damn error'
sys.stdout.write(errstr.format(block = blocks[bidx], bidx = bidx,
cidx = cidx, pad = ' ' * i3, msg = msg))
return
def usage():
sys.stdout.write('Usage: slashpath [ file1 [ file2 [ file3 ... ] ] ]\n\n')
sys.stdout.write('slashpath - /path interpreter\n\
see esolangs.org/wiki//path for more info\n\n')
def main():
if len(sys.argv) == 1: usage()
elif '-s' in sys.argv:
for f in sys.argv[2:]:
slashpath(f, 1)
else:
for f in sys.argv[1:]:
if op.exists(f): slashpath(op.realpath(f))
if __name__ == '__main__': main()