186217d831d70949f9dde6a60f821d3f357558bdfreedfunction tostr(t)
286217d831d70949f9dde6a60f821d3f357558bdfreed    local str = ""
386217d831d70949f9dde6a60f821d3f357558bdfreed    for k, v in next, t do
486217d831d70949f9dde6a60f821d3f357558bdfreed        if #str > 0 then
586217d831d70949f9dde6a60f821d3f357558bdfreed            str = str .. ", "
686217d831d70949f9dde6a60f821d3f357558bdfreed        end
786217d831d70949f9dde6a60f821d3f357558bdfreed        if type(k) == "number" then
886217d831d70949f9dde6a60f821d3f357558bdfreed            str = str .. "[" .. k .. "] = "
986217d831d70949f9dde6a60f821d3f357558bdfreed        else
1086217d831d70949f9dde6a60f821d3f357558bdfreed            str = str .. tostring(k) .. " = "
1186217d831d70949f9dde6a60f821d3f357558bdfreed        end
1286217d831d70949f9dde6a60f821d3f357558bdfreed        if type(v) == "table" then
1386217d831d70949f9dde6a60f821d3f357558bdfreed            str = str .. "{ " .. tostr(v) .. " }"
1486217d831d70949f9dde6a60f821d3f357558bdfreed        elseif type(v) == "string" then
1586217d831d70949f9dde6a60f821d3f357558bdfreed            str = str .. '"' .. v .. '"'
1686217d831d70949f9dde6a60f821d3f357558bdfreed        else
1786217d831d70949f9dde6a60f821d3f357558bdfreed            str = str .. tostring(v)
1886217d831d70949f9dde6a60f821d3f357558bdfreed        end
1986217d831d70949f9dde6a60f821d3f357558bdfreed    end
2086217d831d70949f9dde6a60f821d3f357558bdfreed    return str
2186217d831d70949f9dde6a60f821d3f357558bdfreedend
2286217d831d70949f9dde6a60f821d3f357558bdfreed
2386217d831d70949f9dde6a60f821d3f357558bdfreedfunction trim_ws(s)
2486217d831d70949f9dde6a60f821d3f357558bdfreed    return s:match("^%s*(.*)")
2586217d831d70949f9dde6a60f821d3f357558bdfreedend
2686217d831d70949f9dde6a60f821d3f357558bdfreed
2786217d831d70949f9dde6a60f821d3f357558bdfreedfunction count_hypens(s)
2886217d831d70949f9dde6a60f821d3f357558bdfreed    local leftover = s:match("^-*(.*)")
2986217d831d70949f9dde6a60f821d3f357558bdfreed    return string.len(s) - string.len(leftover)
3086217d831d70949f9dde6a60f821d3f357558bdfreedend
3186217d831d70949f9dde6a60f821d3f357558bdfreed
3286217d831d70949f9dde6a60f821d3f357558bdfreedfunction pretty_print_slide(slide)
3386217d831d70949f9dde6a60f821d3f357558bdfreed    io.write("{\n")
3407dada770b0af4955031806f0c1b8016fa49b65ereed    if slide.transition then
3507dada770b0af4955031806f0c1b8016fa49b65ereed        io.write("   transition = \"", slide.transition, "\",\n")
3607dada770b0af4955031806f0c1b8016fa49b65ereed    end
3786217d831d70949f9dde6a60f821d3f357558bdfreed    for i = 1, #slide do
3886217d831d70949f9dde6a60f821d3f357558bdfreed        local node = slide[i]
3986217d831d70949f9dde6a60f821d3f357558bdfreed        for j = 0, node.indent do
4086217d831d70949f9dde6a60f821d3f357558bdfreed            io.write("   ")
4186217d831d70949f9dde6a60f821d3f357558bdfreed        end
4286217d831d70949f9dde6a60f821d3f357558bdfreed        io.write("{ ")
4386217d831d70949f9dde6a60f821d3f357558bdfreed        io.write(tostr(node))
4486217d831d70949f9dde6a60f821d3f357558bdfreed        io.write(" },\n")
4586217d831d70949f9dde6a60f821d3f357558bdfreed    end
4686217d831d70949f9dde6a60f821d3f357558bdfreed    io.write("},\n")
4786217d831d70949f9dde6a60f821d3f357558bdfreedend
4886217d831d70949f9dde6a60f821d3f357558bdfreed
4986217d831d70949f9dde6a60f821d3f357558bdfreedfunction pretty_print_slides(slides)
5086217d831d70949f9dde6a60f821d3f357558bdfreed    io.write("gSlides = {\n")
5186217d831d70949f9dde6a60f821d3f357558bdfreed    for i = 1, #slides do
5286217d831d70949f9dde6a60f821d3f357558bdfreed        pretty_print_slide(slides[i])
5386217d831d70949f9dde6a60f821d3f357558bdfreed    end
5486217d831d70949f9dde6a60f821d3f357558bdfreed    io.write("}\n")
5586217d831d70949f9dde6a60f821d3f357558bdfreedend
5686217d831d70949f9dde6a60f821d3f357558bdfreed
57bb8a0ababab1aa2693a2a97733524ee367da1791reedfunction parse_attr(s, lvalue)
58bb8a0ababab1aa2693a2a97733524ee367da1791reed    local ts = "^<%s*" .. lvalue .. "%s*=%s*(%a+)%s*>$"
59bb8a0ababab1aa2693a2a97733524ee367da1791reed    return s:match(ts)
6007dada770b0af4955031806f0c1b8016fa49b65ereedend
6107dada770b0af4955031806f0c1b8016fa49b65ereed
62bb8a0ababab1aa2693a2a97733524ee367da1791reedfunction flush(slides, block)
63bb8a0ababab1aa2693a2a97733524ee367da1791reed    if #block > 0 then
64bb8a0ababab1aa2693a2a97733524ee367da1791reed        slides[#slides + 1] = block
65bb8a0ababab1aa2693a2a97733524ee367da1791reed        return {}
66bb8a0ababab1aa2693a2a97733524ee367da1791reed    end
67bb8a0ababab1aa2693a2a97733524ee367da1791reed    return block
68de330ffc5632b91a1025235e4633a1ddbb846aa4reedend
69de330ffc5632b91a1025235e4633a1ddbb846aa4reed
7007dada770b0af4955031806f0c1b8016fa49b65ereedfunction parse_file(file)
7107dada770b0af4955031806f0c1b8016fa49b65ereed    local slides = {}
7207dada770b0af4955031806f0c1b8016fa49b65ereed    local block = {}
7307dada770b0af4955031806f0c1b8016fa49b65ereed
7407dada770b0af4955031806f0c1b8016fa49b65ereed    for line in file:lines() do
7507dada770b0af4955031806f0c1b8016fa49b65ereed        local s = trim_ws(line)
7607dada770b0af4955031806f0c1b8016fa49b65ereed        if #s == 0 then   -- done with a block
77bb8a0ababab1aa2693a2a97733524ee367da1791reed            block = flush(slides, block)
7807dada770b0af4955031806f0c1b8016fa49b65ereed        else
79bb8a0ababab1aa2693a2a97733524ee367da1791reed            local transition_type = parse_attr(s, "transition")
80bb8a0ababab1aa2693a2a97733524ee367da1791reed            local blockstyle = parse_attr(s, "blockstyle")
8107dada770b0af4955031806f0c1b8016fa49b65ereed            if transition_type then
8207dada770b0af4955031806f0c1b8016fa49b65ereed                block["transition"] = transition_type
83de330ffc5632b91a1025235e4633a1ddbb846aa4reed            elseif blockstyle then
84de330ffc5632b91a1025235e4633a1ddbb846aa4reed                block["blockstyle"] = blockstyle
8507dada770b0af4955031806f0c1b8016fa49b65ereed            else
86de330ffc5632b91a1025235e4633a1ddbb846aa4reed                if block.blockstyle == "code" then
87de330ffc5632b91a1025235e4633a1ddbb846aa4reed                    block[#block + 1] = { text = line }
88de330ffc5632b91a1025235e4633a1ddbb846aa4reed                else
89de330ffc5632b91a1025235e4633a1ddbb846aa4reed                    local n = count_hypens(s)
90de330ffc5632b91a1025235e4633a1ddbb846aa4reed                    block[#block + 1] = {
91de330ffc5632b91a1025235e4633a1ddbb846aa4reed                        indent = n,
92de330ffc5632b91a1025235e4633a1ddbb846aa4reed                        text = trim_ws(s:sub(n + 1, -1))
93de330ffc5632b91a1025235e4633a1ddbb846aa4reed                    }
94de330ffc5632b91a1025235e4633a1ddbb846aa4reed                end
9507dada770b0af4955031806f0c1b8016fa49b65ereed            end
9607dada770b0af4955031806f0c1b8016fa49b65ereed        end
9707dada770b0af4955031806f0c1b8016fa49b65ereed    end
987b8646669f5b1e2daddf53764bcde62d743ff076reed    flush(slides, block)
997b8646669f5b1e2daddf53764bcde62d743ff076reed
10007dada770b0af4955031806f0c1b8016fa49b65ereed    return slides
10107dada770b0af4955031806f0c1b8016fa49b65ereedend
10207dada770b0af4955031806f0c1b8016fa49b65ereed
103