OILS / opy / _regtest / src / asdl / visitor.py View on Github | oilshell.org

118 lines, 72 significant
1#!/usr/bin/python
2"""
3visitor.py
4"""
5
6from asdl import asdl_ as asdl
7
8
9class AsdlVisitor:
10 """Base class for visitors.
11
12 TODO:
13 - It might be useful to separate this into VisitChildren() / generic_visit()
14 like Python's ast.NodeVisitor does.
15 - Also remove self.f and self.Emit. Those can go in self.output?
16 - Move to common location, since gen_python uses it as well.
17 """
18 def __init__(self, f):
19 self.f = f
20
21 def Emit(self, s, depth, reflow=True):
22 for line in FormatLines(s, depth):
23 self.f.write(line)
24
25 def VisitModule(self, mod):
26 for dfn in mod.dfns:
27 self.VisitType(dfn)
28 self.EmitFooter()
29
30 def VisitType(self, typ, depth=0):
31 if isinstance(typ.value, asdl.Sum):
32 self.VisitSum(typ.value, typ.name, depth)
33 elif isinstance(typ.value, asdl.Product):
34 self.VisitProduct(typ.value, typ.name, depth)
35 else:
36 raise AssertionError(typ)
37
38 def VisitSum(self, sum, name, depth):
39 if asdl.is_simple(sum):
40 self.VisitSimpleSum(sum, name, depth)
41 else:
42 self.VisitCompoundSum(sum, name, depth)
43
44 # Optionally overridden.
45 def VisitProduct(self, value, name, depth):
46 pass
47 def VisitSimpleSum(self, value, name, depth):
48 pass
49 def VisitCompoundSum(self, value, name, depth):
50 pass
51 def EmitFooter(self):
52 pass
53
54
55TABSIZE = 2
56MAX_COL = 80
57
58# Copied from asdl_c.py
59
60def _ReflowLines(s, depth):
61 """Reflow the line s indented depth tabs.
62
63 Return a sequence of lines where no line extends beyond MAX_COL when properly
64 indented. The first line is properly indented based exclusively on depth *
65 TABSIZE. All following lines -- these are the reflowed lines generated by
66 this function -- start at the same column as the first character beyond the
67 opening { in the first line.
68 """
69 size = MAX_COL - depth * TABSIZE
70 if len(s) < size:
71 return [s]
72
73 lines = []
74 cur = s
75 padding = ""
76 while len(cur) > size:
77 i = cur.rfind(' ', 0, size)
78 # XXX this should be fixed for real
79 if i == -1 and 'GeneratorExp' in cur:
80 i = size + 3
81 assert i != -1, "Impossible line %d to reflow: %r" % (size, s)
82 lines.append(padding + cur[:i])
83 if len(lines) == 1:
84 # find new size based on brace
85 j = cur.find('{', 0, i)
86 if j >= 0:
87 j += 2 # account for the brace and the space after it
88 size -= j
89 padding = " " * j
90 else:
91 j = cur.find('(', 0, i)
92 if j >= 0:
93 j += 1 # account for the paren (no space after it)
94 size -= j
95 padding = " " * j
96 cur = cur[i + 1:]
97 else:
98 lines.append(padding + cur)
99 return lines
100
101
102def FormatLines(s, depth, reflow=True):
103 """Make the generated code readable.
104
105 Args:
106 depth: controls indentation
107 reflow: line wrapping.
108 """
109 if reflow:
110 lines = _ReflowLines(s, depth)
111 else:
112 lines = [s]
113
114 result = []
115 for line in lines:
116 line = (" " * TABSIZE * depth) + line + "\n"
117 result.append(line)
118 return result