Fix several bugs to get Python scanner/parser basically working, processes ../tests...
[pilex.git] / work.py
1 import sys
2 import element
3
4 def yychunk_line(root, fin):
5   line = fin.readline()
6   while len(line):
7     element.set_text(root, -1, element.get_text(root, -1) + line)
8     yield
9     line = fin.readline()
10
11 def yychunk_block(root, fin, count):
12   block = fin.read(count)
13   while len(block):
14     element.set_text(root, -1, element.get_text(root, -1) + line)
15     yield
16     block = fin.read(count)
17
18 def replace_with_element(root, pos0, off0, pos1, off1, child):
19   if pos0 < 0:
20     pos0, off0 = element.to_start_relative(root, pos0, off0)
21   if pos1 < 0:
22     pos1, off1 = element.to_start_relative(root, pos1, off1)
23   count = pos1 - pos0
24   assert count >= 0
25
26   temp = element.get_text(root, pos1)
27   root[pos0:pos1] = [child]
28   element.set_text(root, pos0 + 1, temp[off1:])
29   if count != 0:
30     temp = element.get_text(root, pos0)
31   element.set_text(root, pos0, temp[:off0])
32
33 def replace_with_text(root, mark, i, j, text):
34   (pos0, off0) = mark[i]
35   (pos1, off1) = mark[j]
36   count = pos1 - pos0
37   assert count >= 0
38
39   temp = element.get_tail(root, pos1)
40   del root[pos0 + 1:pos1 + 1]
41   element.set_tail(
42     root,
43     pos0,
44     element.get_tail(root, pos0)[:off0] + text + temp[off1:]
45   )
46
47   if j != i + 1:
48     mark[i + 1:j + 1] = [mark[j]]
49   k = i + 1
50   delta_pos = -count
51   delta_off = off0 + len(text) - off1
52   while k < len(mark):
53     (pos2, off2) = mark[k]
54     if pos2 > pos1:
55       break
56     mark[k] = (pos2 + delta_pos, off2 + delta_off)
57     k += 1
58   if delta_pos != 0:
59     while k < len(mark):
60       (pos2, off2) = mark[k]
61       mark[k] = (pos2 + delta_pos, off2)
62       k += 1
63
64 def replace_with_content(root, mark, i, j, child):
65   text = element.get_tail(child, -1)
66   if len(child) == 0:
67     replace_with_text(root, mark, i, j, text)
68   else:
69     (pos0, off0) = mark[i]
70     (pos1, off1) = mark[j]
71     count = pos1 - pos0
72     assert count >= 0
73   
74     temp = element.get_tail(root, pos1)
75     root[pos0 + 1:pos1 + 1] = child[:]
76     tail = element.get_tail(root, pos0 + len(child))
77     element.set_tail(root, pos0 + len(child), tail + temp[off1:])
78     if count != 0:
79       temp = element.get_tail(root, pos0)
80     element.set_tail(root, pos0, temp[:off0] + text)
81   
82     if j != i + 1:
83       mark[i + 1:j + 1] = [mark[j]]
84     k = i + 1
85     delta_pos = len(child) - count
86     delta_off = len(tail) - off1
87     while k < len(mark):
88       (pos2, off2) = mark[k]
89       if pos2 > pos1:
90         break
91       mark[k] = (pos2 + delta_pos, off2 + delta_off)
92       k += 1
93     if delta_pos != 0:
94       while k < len(mark):
95         (pos2, off2) = mark[k]
96         mark[k] = (pos2 + delta_pos, off2)
97         k += 1
98
99 def extract_element(root, mark, i, j, factory, *args, **kwargs):
100   (pos0, off0) = mark[i]
101   (pos1, off1) = mark[j]
102   count = pos1 - pos0
103   assert count >= 0
104
105   result = factory(*args, **kwargs)
106   result[:] = [i.copy() for i in root[pos0 + 1:pos1 + 1]]
107   tail = element.get_tail(root, pos1)
108   if count == 0:
109     element.set_tail(result, -1, tail[off0:off1])
110   else:
111     element.set_tail(result, count - 1, tail[:off1])
112     tail = element.get_tail(root, pos0)
113     element.set_tail(result, -1, tail[off0:])
114   return result
115
116 def extract_text(root, mark, i, j):
117   (pos0, off0) = mark[i]
118   (pos1, off1) = mark[j]
119   #result = [element.get_tail(root, i) for i in range(pos0, pos1 + 1)]
120   #result[-1] = result[-1][:off1]
121   #result[0] = result[0][off0:]
122   #return ''.join(result)
123   assert pos1 == pos0
124   return element.get_tail(root, pos0)[off0:off1]
125
126 def apply_markup(root, pos0, off0, pos1, off1, factory, *args, **kwargs):
127   if pos0 < 0:
128     pos0, off0 = element.to_start_relative(root, pos0, off0)
129   if pos1 < 0:
130     pos1, off1 = element.to_start_relative(root, pos1, off1)
131   count = pos1 - pos0
132   assert count >= 0
133
134   child = factory(*args, **kwargs)
135   child[:] = root[pos0:pos1]
136
137   tail = element.get_text(root, pos1)
138   # at present, if count > 0, child[-1] is shared with root[pos1 - 1],
139   # so we cannot change child[-1].tail until after the replacement
140   if count == 0:
141     replace_with_element(root, pos0, off0, pos1, off1, child)
142     element.set_text(child, 0, tail[off0:off1])
143   else:
144     temp = element.get_text(root, pos0)
145     replace_with_element(root, pos0, off0, pos1, off1, child)
146     element.set_text(child, count, tail[:off1])
147     element.set_text(child, 0, temp[off0:])
148   return child
149
150 def dump(root, mark):
151   i = 0
152   pos = -1
153   result = ''
154   while True:
155     assert i >= len(mark) or mark[i][0] >= pos
156     tail = element.get_tail(root, pos) 
157     off = 0
158     while off < len(tail) or (i < len(mark) and mark[i][0] == pos):
159       end = len(tail) if i >= len(mark) or mark[i][0] != pos else mark[i][1]
160       if end > off:
161         result += tail[off:end].replace('\n', '(lf)').replace('\t', '(tab)')
162         off = end
163       if i < len(mark) and mark[i][0] == pos:
164         result += '({0:d})'.format(i)
165         i += 1
166     pos += 1
167     if pos >= len(root):
168       break
169     result += '({0:s}{1:d})'.format(root[pos].tag, pos)
170   assert i >= len(mark)
171   result += '(eof)'
172   sys.stdout.write('{0:s}\n'.format(result[-159:])) #79:]))
173   sys.stdout.flush()