156 lines
4.0 KiB
Python
156 lines
4.0 KiB
Python
#!/usr/bin/python
|
|
|
|
from os import system
|
|
import re
|
|
from socket import socket, AF_INET, SOCK_STREAM
|
|
from subprocess import run, TimeoutExpired
|
|
from sys import argv, stdin, stdout
|
|
from tempfile import mkdtemp, mkstemp
|
|
|
|
sandbox = None
|
|
irc = None
|
|
|
|
template = '''
|
|
|0100
|
|
;on-console #10 DEO2
|
|
|
|
( start ) %s ( end ) BRK
|
|
|
|
@on-console ( -> BRK )
|
|
#05 DEI ,emit-wst/n STR
|
|
;wst print
|
|
|
|
@dump-wst
|
|
#04 DEI #01 GTH ?&next !emit-wst &next STH !dump-wst
|
|
|
|
@emit-wst
|
|
#05 DEI LIT [ &n $1 ] GTH ?&next #0a18 DEO !start-rst
|
|
&next STHr emit #2018 DEO !emit-wst
|
|
|
|
@start-rst
|
|
;rst print
|
|
|
|
@dump-rst
|
|
#05 DEI #00 GTH ?&next !emit-rst &next STHr !dump-rst
|
|
|
|
@emit-rst
|
|
#04 DEI #01 GTH ?&next #0a18 DEO #800f DEO BRK
|
|
&next emit #2018 DEO !emit-rst
|
|
|
|
@print ( addr* -> )
|
|
LDAk DUP ?{ POP POP2 JMP2r } #18 DEO INC2 !print
|
|
|
|
@emit
|
|
DUP #04 SFT ,&ch JSR
|
|
&ch #0f AND DUP #09 GTH #27 MUL ADD #30 ADD #18 DEO JMP2r
|
|
|
|
@rst "rst 20 00
|
|
@wst "wst 20 00
|
|
'''
|
|
|
|
def write_rom(path, s):
|
|
f = open(path, 'w')
|
|
prog = template % s
|
|
f.write(prog)
|
|
f.close()
|
|
|
|
def execute(s, sandbox=None, timeout=2.0):
|
|
_, tmp_tal = mkstemp(suffix='.tal', prefix='uxnrepl')
|
|
_, tmp_rom = mkstemp(suffix='.rom', prefix='uxnrepl')
|
|
write_rom(tmp_tal, s)
|
|
try:
|
|
res = run(['uxnasm', tmp_tal, tmp_rom], cwd=sandbox, capture_output=True, timeout=timeout)
|
|
except TimeoutExpired:
|
|
return b'uxnasm: timed out'
|
|
if res.returncode != 0:
|
|
return res.stderr
|
|
try:
|
|
res = run(['uxncli', tmp_rom, 'trigger'], cwd=sandbox, capture_output=True, timeout=timeout)
|
|
except TimeoutExpired:
|
|
return b'uxncli: timed out'
|
|
return res.stdout
|
|
|
|
def repl():
|
|
print('uxnrepl (ctrl-d to exit)')
|
|
while True:
|
|
stdout.write('> ')
|
|
stdout.flush()
|
|
s = stdin.readline()
|
|
if not s:
|
|
print('bye!')
|
|
break
|
|
stdout.write(execute(s).decode('utf-8'))
|
|
stdout.flush()
|
|
|
|
ping_re = re.compile(br'PING (.+)$')
|
|
|
|
def send(msg, quiet=False):
|
|
if not quiet:
|
|
print('>>> %r' % msg)
|
|
irc.send(msg + b'\r\n')
|
|
|
|
def recv():
|
|
msg = irc.recv(2040)
|
|
if not ping_re.match(msg):
|
|
print('<<< %r' % msg)
|
|
return msg
|
|
|
|
def evaluate(msg):
|
|
output = execute(msg.decode('utf-8'), sandbox=sandbox)
|
|
lines = [s.strip() for s in output.split(b'\n')]
|
|
interesting = [s for s in lines if s and s != 'wst' and s != 'rst']
|
|
result = b' | '.join(interesting)
|
|
print('*** executing %r gave %r -> %r -> %r' % (msg, output, interesting, result))
|
|
return result
|
|
|
|
def ircbot(server, nick, channel):
|
|
global sandbox, irc
|
|
sandbox = mkdtemp(prefix='uxnrepl')
|
|
irc = socket(AF_INET, SOCK_STREAM)
|
|
|
|
irc.connect((server, 6667))
|
|
send(b"USER %s %s %s :bot for testing uxntal code" % (nick, nick, nick))
|
|
send(b"NICK %s" % nick)
|
|
send(b"JOIN %s" % channel)
|
|
|
|
chan_msg_re = re.compile(br':([^!]+)![^ ]+ PRIVMSG ([^ ]+) :' + nick + br': (.*)$')
|
|
priv_msg_re = re.compile(br':([^!]+)![^ ]+ PRIVMSG ' + nick + br' :(.*)$')
|
|
|
|
while True:
|
|
text = recv()
|
|
|
|
m = ping_re.match(text)
|
|
if m:
|
|
send(b'PONG %s' % m.group(1).strip(), quiet=True)
|
|
continue
|
|
|
|
m = chan_msg_re.match(text)
|
|
if m and m.group(2) == channel:
|
|
user = m.group(1)
|
|
msg = m.group(3).strip()
|
|
result = evaluate(msg)
|
|
send(b'PRIVMSG %s :%s: %s' % (channel, user, result))
|
|
continue
|
|
|
|
m = priv_msg_re.match(text)
|
|
if m:
|
|
user = m.group(1)
|
|
msg = m.group(2).strip()
|
|
result = evaluate(msg)
|
|
send(b'PRIVMSG %s :%s' % (user, result))
|
|
continue
|
|
|
|
def main():
|
|
if argv[1:] == [] or argv[1:] == ["repl"]:
|
|
repl()
|
|
elif argv[1] == "bot" and len(argv) == 5:
|
|
server, nick, channel = argv[2:]
|
|
ircbot(server, nick.encode('utf-8'), channel.encode('utf-8'))
|
|
else:
|
|
print("usage: %s [repl]" % argv[0])
|
|
print(" %s bot <server> <nick> <channel>" % argv[0])
|
|
exit(1)
|
|
|
|
if __name__ == "__main__":
|
|
main()
|