-
Notifications
You must be signed in to change notification settings - Fork 0
/
medik
executable file
·160 lines (138 loc) · 5.84 KB
/
medik
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
#!/usr/bin/env python3.10
from pathlib import Path
from argparse import ArgumentParser
from fractions import Fraction
import asyncio, logging, os, sys, json, tempfile, json, re
base_dir = Path(__file__).parents[0]
kompiled_dir = base_dir / '.build' / 'llvm-exec' / 'medik-llvm-kompiled'
krelease_dir = base_dir / 'ext' / 'k' / 'k-distribution' / 'target' / 'release' / 'k'
kbin_dir = krelease_dir / 'bin'
def set_env():
path_entires = [ kbin_dir ]
os.environ['PATH'] = str(kbin_dir.resolve()) \
+ os.pathsep + os.environ['PATH']
background_tasks = set()
message_queue = asyncio.Queue()
async def parse_json_stream(json_stream):
open_brace_count = 0
close_brace_count = 0
last_scan_index = 0
json_byte_str = b''
try:
while True:
json_byte_str += await json_stream.readuntil(b'}')
open_brace_count += json_byte_str.count(b'{', last_scan_index)
close_brace_count += json_byte_str.count(b'}', last_scan_index)
if len(json_byte_str) == 0:
return None
if open_brace_count == close_brace_count:
obj = json.loads(json_byte_str)
json_byte_str = b''
last_scan_index = 0
open_proce_count = 0
close_brace_count = 0
return obj
last_scan_index = len(json_byte_str)
except asyncio.IncompleteReadError:
return None
async def _sleep(k_process, duration, tid):
logging.info('sleeping for duration {} for tid {}'.format(duration, tid))
await asyncio.sleep(duration)
k_process.stdin.write(json.dumps({ 'tid' : tid
, 'action' : 'sleepResponse' }, sort_keys=True).encode('utf-8'))
await k_process.stdin.drain()
logging.info('sleep complete message sent for tid {}'.format(tid))
def process_rats(out_json):
if out_json.get('args') != None:
processed_args = []
rat_re = re.compile(r'\<(-?\d+),(\d+)\>Rat')
for arg in out_json['args']:
if isinstance(arg, str) and rat_re.match(arg) != None:
rat_match = rat_re.match(arg)
processed_args.append(Fraction( int(rat_match.group(1))
, int(rat_match.group(2))))
else:
processed_args.append(arg)
out_json['args'] = processed_args
return out_json
async def read_stdout(k_process, handler_cb=lambda msg: print(json.dumps(msg))):
while True:
logging.info('waiting for k:')
out_json = await parse_json_stream(k_process.stdout)
if out_json == None:
break;
try:
match out_json.get('action'):
case 'print':
processed_json = process_rats(out_json)
print(*map(lambda x: float(x) if isinstance(x, Fraction) else x
, processed_json['args'])
, end='', flush=True)
case 'sleep':
sleep_task = asyncio.create_task(_sleep( k_process
, out_json['duration']
, out_json['tid']))
case 'exit':
break
case _:
# Print whatever we got
handler_cb(out_json)
except (ValueError, AttributeError) as e:
sys.err.write(str(e))
return None
async def read_stderr(k_process):
while True:
err = await k_process.stderr.read()
if not err:
break
else:
sys.stderr.write(err.decode('utf-8'))
sys.stderr.flush()
async def write_stdin(k_process, in_file=None):
if in_file != None:
with open(in_file) as in_file_obj:
in_data = in_file_obj.read()
logging.info('sending to k: {}'.format(in_data))
k_process.stdin.write(in_data.encode('utf-8'))
await k_process.stdin.drain()
logging.info('sending to k complete')
async def krun(pgm_file, in_file=None):
set_env()
k_command = ( 'krun' , ['--definition' , str(kompiled_dir.resolve())
, '--output' , 'none'
, pgm_file ])
k_process = await asyncio.create_subprocess_exec( k_command[0]
, *k_command[1]
, stdin=asyncio.subprocess.PIPE
, stdout=asyncio.subprocess.PIPE
, stderr=asyncio.subprocess.PIPE)
await asyncio.gather( read_stdout(k_process)
, write_stdin(k_process, in_file)
, read_stderr(k_process))
return k_process.returncode
async def main():
parser = ArgumentParser(description='MediK Interpreter')
parser.add_argument('-in', '--in-file'
, help='File with input messages'
, nargs=1
, dest='in_file')
parser.add_argument('pgm_file'
, metavar='PGM_FILE'
, help='MediK file to run')
parser.add_argument('-v', '--verbose'
, help='print verbose logs'
, action='store_const'
, dest='loglevel'
, const=logging.INFO
)
args = parser.parse_args()
logging.basicConfig(level=args.loglevel, format='%(message)s')
retval = 0
if args.in_file != None:
retval = await krun(args.pgm_file, args.in_file[0])
else:
retval = await krun(args.pgm_file)
return retval
if __name__ == "__main__":
retval = asyncio.run(main())
sys.exit(retval)