Last active
June 1, 2018 14:44
-
-
Save HarryR/768da01bc51c11dd4e76067fda4057ca to your computer and use it in GitHub Desktop.
Small programming language in Python, supports subexpressions
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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