Partially update state annotations section in the prototype chapter.
[matthijs/master-project/report.git] / pret-trans.lua
1 -- filename : type-trans.lua
2 -- comment  : Pretty printing of core transformations. Parses a specific
3 --            syntax, consisting of a before / after with a dashed lined in
4 --            between, and some extra conditions to the right of the line.
5 --            Recreates this layout using frames and line commands.
6 -- author   : Matthijs Kooijman, Universiteit Twente, NL
7 -- copyright: Matthijs Kooijman
8 -- license  : None
9
10 local utf = unicode.utf8
11
12 local vis = buffers.newvisualizer("trans")
13
14 local commands = {}
15 -- A command to create a horizontal rule.
16 commands.rule = "\\HLine[width=.40 * \\the\\textwidth]"
17 -- Typing environment to use for the stuff before and after the line. Will be
18 -- prefixed with \start and \stop automatically.
19 commands.beforeenv = "unboxedlambda"
20 commands.afterenv = "unboxedlambda"
21 -- Frame commands to use for the left (before + line + after) and right
22 -- (conditions) parts. Should include an opening {, which will be closed
23 -- automatically.
24 commands.leftframe = "\\framed[offset=0mm,location=middle,strut=no,align=right,frame=off,width=.48\\textwidth]{"
25 commands.rightframe = "\\framed[offset=0mm,location=middle,strut=no,align=right,frame=off,width=.48\\textwidth]{"
26
27 -- A table to keep the lines in this buffer, so we can process them all at
28 -- once at the end.
29 local lines
30
31 -- Some helper functions
32 local function ltrim(s)
33     return (string.gsub(s, "^%s*", ""))
34 end
35
36 local function rtrim(s)
37     return (string.gsub(s, "%s*$", ""))
38 end
39
40 -- Insert n blank lines
41 local function blanks(n)
42     for i = 1,n do
43         buffers.visualizers.handlers.default.empty_line()
44     end
45 end
46
47 -- Prettyprint the given lines using the given pretty printer
48 local function prettyprint(ppr, lines)
49     -- Change the current visualizer
50     buffers.setvisualizer('lam')
51
52     -- Output the lines
53     buffers.hooks.begin_of_display()
54     line = 0
55     for i = 1,#lines do
56         _, line = buffers.typeline(lines[i], i, #lines, line)
57     end
58     buffers.hooks.end_of_display()
59
60     -- Change the visualizer back
61     buffers.setvisualizer('trans')
62 end
63
64 -- Capture all lines, without generating any output
65 function vis.begin_of_display()
66     lines = {}
67 end
68 function vis.begin_of_line(n)
69     -- Don't generate output here
70 end
71 function vis.flush_line(str, nested)
72     table.insert(lines, str)
73     -- Don't generate output here
74 end
75 function vis.end_of_line(n)
76     -- Don't generate output here
77 end
78 function vis.empty_line()
79     table.insert(lines, '')
80     -- Don't generate output here
81 end
82
83 -- We do the actual work here. Process all the lines in the buffer and
84 -- generate output for them.
85 function vis.end_of_display()
86     -- Find the horizontal rule, and see how long it is.
87     len = nil
88     for i = 1,#lines do
89         match = utf.match(lines[i], "^%-%-%-*")
90         if match then
91             len = utf.len(match)
92             break
93         end
94     end
95   
96     if not len then
97         error("No horizontal separator found in:\n" .. table.concat(lines, "\n"))
98     end
99
100     -- Split the input in three parts. Stuff before the line, stuff
101     -- after the line, stuff to the right of the line.
102     before, after, rights = {}, {}, {}
103     found_line = false
104     for i = 1,#lines do
105         line = lines[i]
106         -- Split the line into a left and right part
107         left = rtrim(utf.sub(line, 1, len))
108         right = ltrim(utf.sub(line, len + 1))
109         if utf.match(left, "^%-%-%-*") then
110             found_line = true
111         else
112             if utf.len(left) > 0 then
113                 if not found_line then
114                     table.insert(before, left)
115                 else
116                     table.insert(after, left)
117                 end
118             end
119         end
120         if utf.len(right) > 0 then
121             table.insert(rights, right)
122         end
123     end
124
125     --
126     -- Real output starts here
127     --
128
129     -- Let all the lambda pretty printing in this buffer use shared subscript
130     -- detection
131     tex.sprint("\\directlua{buffers.visualizers.handlers.lam.begin_of_block()}")
132
133     -- Ensure the left and right frames end up next to each other.
134     tex.sprint("\\dontleavehmode")
135
136     -- Open and fill the left frame
137     tex.sprint(commands.leftframe)
138
139     tex.sprint("\\start" .. commands.beforeenv)
140
141     tex.sprint(table.concat(before, "\n"))
142
143     tex.sprint("\\stop" .. commands.beforeenv)
144
145     tex.sprint(commands.rule)
146
147     tex.sprint("\\start" .. commands.afterenv)
148
149     tex.sprint(table.concat(after, "\n"))
150
151     tex.sprint("\\stop" .. commands.afterenv)
152
153     -- Close the left frame
154     tex.sprint("}")
155
156     -- Open and fill the right frame
157     tex.sprint(commands.rightframe)
158
159     -- Insert spacer blank lines to align the middle condition with the
160     -- conclusion rule
161     n_blanks = #before - math.ceil((#rights - 1) / 2)
162     n_blanks = math.max(0, n_blanks)
163     blanks(n_blanks)
164
165     -- Print the conditions
166     for i = 1,#rights do
167         tex.sprint(rights[i])
168         buffers.visualizers.handlers.default.end_of_line()
169     end
170
171     -- Fill up the remaining space with blanks
172     n_blanks = (#before + 1 + #after) - (n_blanks + #rights)
173     n_blanks = math.max(0, n_blanks)
174     blanks(n_blanks)
175
176     -- Close the right frame 
177     tex.sprint("}")
178
179     tex.sprint("\\directlua{buffers.visualizers.handlers.lam.end_of_block()}")
180     
181     -- Clean up
182     lines = {}
183 end
184
185 -- vim: set sw=4 sts=4 expandtab ai: