c5e0cd94181a13dceeeb00c0fa5809349e01e2b1
[jackhill/mal.git] / impls / xslt / harness.py
1 import time
2 import os
3 import readline
4 import sys
5 import xml.etree.ElementTree as ET
6 from threading import Thread
7 from threading import Lock
8 from collections import deque
9
10 fname = sys.argv[1]
11 args = sys.argv[2:]
12 tree = ET.Element('mal')
13
14 if len(args) > 0:
15 args0 = args[0]
16 ET.SubElement(tree, 'argv')
17 for a in tree.iter('mal'):
18 for a in a.iter('argv'):
19 for arg in args[1:]:
20 ET.SubElement(a, 'arg').text = arg
21 ET.SubElement(tree, 'no_repl')
22
23 tree = ET.ElementTree(tree)
24 stdout = sys.stdout
25
26 try:
27 readline.read_history_file('.xslt_mal_history')
28 except:
29 pass
30
31 finished = False
32 sem = Lock()
33 init_t = time.time() * 1000
34 readline_queue = deque()
35 os.system('rm -rf xsl_error.xml')
36 os.system('mkfifo xsl_error.xml')
37
38 def setup_request_file():
39 os.system('rm -rf xsl_input-string')
40 os.system('mkfifo xsl_input-string')
41
42
43 def read_nonblocking(path, bufferSize=100, timeout=.1):
44 grace = True
45 result = []
46 pipe = os.open(path, os.O_RDONLY | os.O_NONBLOCK)
47 try:
48 while True:
49 try:
50 buf = os.read(pipe, bufferSize)
51 if not buf:
52 break
53 else:
54 content = buf.decode("utf-8")
55 line = content.split("\n")
56 result.extend(line)
57 except OSError as e:
58 if e.errno == 11 and grace:
59 # grace period, first write to pipe might take some time
60 # further reads after opening the file are then successful
61 time.sleep(timeout)
62 grace = False
63 else:
64 break
65
66 except OSError as e:
67 if e.errno == errno.ENOENT:
68 # os.close(pipe)
69 pipe = None
70 else:
71 raise e
72
73 os.close(pipe)
74 return result
75
76 def serve_one_request():
77 res = read_nonblocking('xsl_error.xml', 1024)
78 if len(res) == 0:
79 return
80 for res in res:
81 try:
82 xtree = ET.fromstring("<data>" + res.strip('\x00') + "</data>")
83 # stdout.write(xtree.attrib['kind'])
84 for req in xtree:
85 if req.attrib['kind'] == 'readline':
86 x = None
87 if len(readline_queue) > 0:
88 x = readline_queue.popleft()
89 else:
90 x = input(req.attrib['value'])
91 with open('xsl_input-string', 'w') as fx:
92 fx.write(x)
93 # stdout.write(' = ' + x)
94 elif req.attrib['kind'] == 'display':
95 stdout.write(req.attrib['value'] + '\n')
96 elif req.attrib['kind'] == 'time':
97 x = time.time() * 1000 - init_t
98 # stdout.write(' = ' + str(int(x)))
99 with open('xsl_input-string', 'w') as fx:
100 fx.write(str(int(x)))
101 # stdout.write('\n')
102 elif req.attrib['kind'] == 'xpath-eval':
103 xpath = req.attrib['value']
104 with open('xsl-eval.xslt', 'w') as f:
105 f.write(f'<?xml version="1.0" encoding="UTF-8"?><xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fn="http://www.w3.org/2005/02/xpath-functions" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:map="http://www.w3.org/2005/xpath-functions/map" xmlns:env="ENV" xmlns:core="CORE" exclude-result-prefixes="env core xs xsl map fn"><xsl:output omit-xml-declaration="yes"/><xsl:template match="/"><xsl:sequence select="{xpath}" /></xsl:template></xsl:stylesheet>')
106 with open('xsl-null.xml', 'w') as f:
107 f.write(req.attrib['context'])
108
109 if os.system(f'saxon -xsl:xsl-eval.xslt -s:xsl-null.xml > xsl-eval_output.xml'):
110 x = ''
111 else:
112 with open('xsl-eval_output.xml', 'r') as f:
113 x = f.read()
114 with open('xsl_input-string', 'w') as fx:
115 fx.write(x)
116 else:
117 stdout.write("UNKNOWN REQUEST " + req.attrib['kind'])
118 # stdout.write('\n')
119 except Exception as e:
120 # if str(e) != 'no element found: line 1, column 0':
121 # f.seek(0)
122 # print(e, list(x for x in f.read()))
123 return
124 # with open('xsl_error.xml', 'w') as f:
125 # f.write('')
126
127 def serve_requests():
128 global finished
129 setup_request_file()
130 while not finished:
131 try:
132 serve_one_request()
133 except Exception as e:
134 # print(e)
135 pass
136
137
138 th = Thread(target=serve_requests)
139 th.start()
140
141 def transform(do_print=True):
142 global tree
143
144 tree.write('xslt_input.xml')
145 if os.system(f'saxon -xsl:"{fname}" -s:xslt_input.xml -TP:perf.html > xslt_output.xml 2> xsl_error.xml'):
146 return
147 tree = ET.parse('xslt_output.xml')
148 if do_print:
149 stdout = ''
150 for a in tree.iter('mal'):
151 for a in a.iter('stdout'):
152 stdout = a
153 print(stdout.text)
154 stdout.clear()
155 del stdout
156
157
158 if len(args) > 0:
159 readline_queue.append(f'(load-file "{args0}")')
160 transform(do_print=False)
161 else:
162 if fname == 'stepA_mal.xslt':
163 readline_queue.append('(println (str "Mal [" *host-language* "]"))')
164 transform(do_print=False)
165 else:
166 transform()
167 readline.write_history_file('.xslt_mal_history')
168
169 finished = True
170 th.join()