Skip to content

Instantly share code, notes, and snippets.

@HarryR
Last active June 1, 2018 14:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save HarryR/768da01bc51c11dd4e76067fda4057ca to your computer and use it in GitHub Desktop.
Save HarryR/768da01bc51c11dd4e76067fda4057ca to your computer and use it in GitHub Desktop.
Small programming language in Python, supports subexpressions
#!/usr/bin/env python
from __future__ import print_function
import traceback
import sys
import json
import re
LEX_RX = re.compile(r'("[^"]+"|[^a-zA-Z0-9\$\s]|\$?[a-zA-Z0-9]+)')
CMDS = dict(
echo=lambda *x: print(*x),
loop=lambda *x: builtin_loop(*x),
line=lambda *x: sys.stdin.readline().rstrip('\n'),
eval=lambda *x: map(rs_run, x)[-1],
)
def builtin_loop(*args):
while True:
for arg in args:
rs_run(arg)
def rs_arg(arg):
if arg[0] == '"':
return json.loads(arg)
return arg
def rs_lex(script):
return map(rs_arg, LEX_RX.findall(script))
def rs_exec(*args):
cmd = args[0]
if cmd in CMDS:
return CMDS[cmd](*args[1:])
raise RuntimeError(
' '.join(["Unknown", ' '.join(args)]))
def rs_eval(script):
N = 0
args = []
result = None
while script:
N += 1
cmd = script[0]
script = script[1:]
do_exec = not len(script)
if cmd == '[':
skip_N, result = rs_eval(script)
script = script[skip_N:]
N += skip_N
args.append(result)
elif cmd == ']':
do_exec = True
script = None
elif cmd == ';':
do_exec = True
elif cmd[0] == '$':
args.append( rs_exec(cmd[1:]) )
else:
args.append(cmd)
if do_exec:
result = rs_exec(*args)
args = []
return N, result
def rs_run(line):
return rs_eval(rs_lex(line))
def rs_repl(prelude_files=None, readin=sys.stdin, writeout=sys.stdout):
if prelude_files:
for filename in prelude_files:
with open(filename, 'rb') as handle:
for line in handle:
rs_run(line)
# This can be replaced with:
# loop "echo > ; echo [ eval $line ]"
while True:
writeout.write('> ')
writeout.flush()
try:
command = readin.readline()
except KeyboardInterrupt:
continue
except EOFError:
break
if not command:
break
try:
rs_run(command)
except Exception as ex:
traceback.print_exc()
if __name__ == "__main__":
rs_repl(sys.argv[1:])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment