/path/refimpl

:
: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()
Category:Implementations