#!/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 server = "irc.libera.chat" nick = b"uxnbot" channel = b"#uxn" sandbox = None irc = None template = ''' |0100 ( start ) %s ( end ) #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], 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 (.+)$') chan_msg_re = re.compile(br':([^!]+)![^ ]+ PRIVMSG ([^ ]+) :' + nick + br': (.*)$') priv_msg_re = re.compile(br':([^!]+)![^ ]+ PRIVMSG ' + nick + br' :(.*)$') 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(): 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("PRIVMSG nickserv :iNOOPE\r\n") send(b"JOIN %s" % channel) 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: # TODO: plug in server, nick, channel server, nick, channel = argv[2:] ircbot() else: print("usage: %s [repl]" % argv[0]) print(" %s bot " % argv[0]) exit(1) if __name__ == "__main__": main()