summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--rst_context.lua115
-rw-r--r--rst_helpers.lua121
-rw-r--r--rst_parser.lua136
3 files changed, 318 insertions, 54 deletions
diff --git a/rst_context.lua b/rst_context.lua
index 64c2cd6..851bd7e 100644
--- a/rst_context.lua
+++ b/rst_context.lua
@@ -13,9 +13,9 @@
require "lpeg"
-require help = "rst_helpers"
+help = require "rst_helpers"
-local dbg_write = help.dbg_write
+local dbg_write = help.dbg_writef
local C, Cb, Cc, Cg, Cmt, Cp, Cs, Ct, P, R, S, V, match = lpeg.C, lpeg.Cb, lpeg.Cc, lpeg.Cg, lpeg.Cmt, lpeg.Cp, lpeg.Cs, lpeg.Ct, lpeg.P, lpeg.R, lpeg.S, lpeg.V, lpeg.match
@@ -615,36 +615,6 @@ function rst_context.table (str)
end
function rst_context.grid_table (tab)
- local head
- if tab.has_head then
- head = [[
-\\setupTABLE[c][first] [background=color, backgroundcolor=grey, style=\tt]
-\\setupTABLE[c][each] [frame=on]
-\\setupTABLE[r][each] [frame=on]
-\\bTABLE[split=repeat,option=stretch]
-\\bTABLEhead
-\\bTR
- \\bTH first \\eTH
- \\bTH second \\eTH
- \\bTH third \\eTH
- \\bTH fourth \\eTH
-\\eTR
-\\eTABLEhead
-\\bTABLEbody
-]]
- else
- head = [[
-\\setupTABLE[c][each] [frame=on]
-\\setupTABLE[r][each] [frame=on]
-\\bTABLE[split=repeat,option=stretch]
-\\bTABLEbody
-]]
- end
- local tail = [[
-
-\\eTABLEbody
-\\eTABLE
-]]
local body = ""
for i,r in ipairs(tab.rows) do
local isempty = true
@@ -679,18 +649,87 @@ function rst_context.grid_table (tab)
body = body .. row .. "\n" .. [[\\eTR]] .. "\n"
end
end
+ local head
+ if tab.has_head then
+ head = [[
+\\setupTABLE[c][first] [background=color, backgroundcolor=grey, style=\tt]
+\\setupTABLE[c][each] [frame=on]
+\\setupTABLE[r][each] [frame=on]
+\\bTABLE[split=repeat,option=stretch]
+\\bTABLEhead
+\\bTR
+ \\bTH first \\eTH
+ \\bTH second \\eTH
+ \\bTH third \\eTH
+ \\bTH fourth \\eTH
+\\eTR
+\\eTABLEhead
+\\bTABLEbody
+]]
+ else
+ head = [[
+\\setupTABLE[c][each] [frame=on]
+\\setupTABLE[r][each] [frame=on]
+\\bTABLE[split=repeat,option=stretch]
+\\bTABLEbody
+]]
+ end
+ local tail = [[
+
+\\eTABLEbody
+\\eTABLE
+]]
return head .. body .. tail
end
-function rst_context.table_row (tab)
- local tmp = [[\\bTR]]
- for n, cell in ipairs(tab) do
- tmp = tmp .. [[\\bTC]] .. cell .. [[\\eTC]] .. "\n"
+function rst_context.simple_table(tab)
+ local head
+ if tab.has_head then
+ head = [[
+\\setupTABLE[c][first] [background=color, backgroundcolor=grey, style=\tt]
+\\setupTABLE[c][each] [frame=on]
+\\setupTABLE[r][each] [frame=on]
+\\bTABLE[split=repeat,option=stretch]
+\\bTABLEhead
+\\bTR
+ \\bTH first \\eTH
+ \\bTH second \\eTH
+ \\bTH third \\eTH
+\\eTR
+\\eTABLEhead
+\\bTABLEbody
+]]
+ else
+ head = [[
+\\setupTABLE[c][each] [frame=on]
+\\setupTABLE[r][each] [frame=on]
+\\bTABLE[split=repeat,option=stretch]
+\\bTABLEbody
+]]
end
+ local tail = [[
- tmp = tmp .. [[\\eTR
+\\eTABLEbody
+\\eTABLE
]]
- return tmp
+ local body = ""
+ for nr,row in ipairs(tab) do
+ if not row.separator and not row.ignore then
+ dbg_write(">tr>" .. #row)
+ body = body .. [[\\bTR]]
+ for nc,cell in ipairs(row) do
+ dbg_write("%7s | ", cell.content)
+ if cell.span then
+ body = body .. string.format([=[\\bTC[nc=%s]%s\\eTC]=], cell.span, cell.content)
+ else
+ body = body .. [[\\bTC ]] .. cell.content .. [[\\eTC]]
+ end
+ end
+ dbg_write("\n")
+ body = body .. "\\\\eTR\n"
+ end
+ end
+ return head .. body .. tail
end
return rst_context
diff --git a/rst_helpers.lua b/rst_helpers.lua
index acd61ed..fb0dd84 100644
--- a/rst_helpers.lua
+++ b/rst_helpers.lua
@@ -20,13 +20,14 @@ local helpers = {}
helpers.table = {}
helpers.cell = {}
-local function dbg_writef(...)
+function helpers.dbg_writef(...)
if helpers_debug == true then
io.write(string.format(...))
end
end
-helpers.dbg_write = dbg_write
+--helpers.dbg_write = dbg_write
+local dbg_write = helpers.dbg_writef
local patterns = {}
@@ -38,6 +39,9 @@ do
p.bar = P"|"
p.eol = P"\n"
p.last = -P(1)
+ p.space = P" "
+
+ p.dash_or_equals = p.dash + p.equals
p.celldelim = p.bar + p.plus
p.cellcontent = (1 - p.celldelim)
@@ -45,6 +49,16 @@ do
p.cell_line = p.plus * p.dash^1 * #p.plus
p.dashesonly = p.dash^1 * p.last
+ p.col_start = Cp() * p.dash_or_equals^1
+ p.col_stop = p.dash_or_equals^1 * Cp()
+ p.column_starts = p.col_start * ( p.space^1 * p.col_start)^1
+ p.column_stops = p.col_stop * ( p.space^1 * p.col_stop)^1
+
+ p.st_headsep = p.equals^1 * (p.space^1 * p.equals^1)^1
+ p.st_colspan = p.dash^1 * (p.space^1 * p.dash^1)^0 * p.space^0 * p.last
+ p.st_span_starts = Ct(Cp() * p.dash^1 * (p.space^1 * Cp() * p.dash^1)^0)
+ p.st_span_stops = Ct(p.dash^1 * Cp() * (p.space^1 * p.dash^1 * Cp())^0)
+
p.cells = P{
[1] = "cells",
cells = p.celldelim
@@ -457,9 +471,110 @@ function helpers.table.create(raw)
end
end
- self.__draw_debug()
+ --self.__draw_debug()
return self
+end
+
+
+
+-- Check the column boundaries of a simple table.
+function helpers.get_st_boundaries (str)
+ local p = patterns
+ local starts, stops, slices = {}, {}, {}
+ for n, elm in ipairs({ p.column_starts:match(str) }) do
+ slices[n] = { start = elm }
+ starts[elm] = true
+ end
+ for n, elm in ipairs({ p.column_stops :match(str) }) do
+ slices[n]["stop"] = elm
+ stops[elm] = true
+ end
+ return { starts = starts, stops = stops, slices = slices }
+end
+
+function helpers.table.simple(raw)
+ local rows = {}
+ local multispans = {}
+ local bounds = helpers.get_st_boundaries(raw[1])
+ local p = patterns
+
+ for nr=1, #raw do
+ local row = raw[nr]
+ if p.st_colspan:match(row) then
+ local spans = {}
+ spans.starts = p.st_span_starts:match(row)
+ spans.stops = p.st_span_stops :match(row)
+ local all_match = true
+ for n=1, #spans.starts do -- check if they match the table layout
+ local start = spans.starts[n]
+ local stop = spans.stops[n]
+ if not bounds.starts[start] or
+ not bounds.stops[stop] then
+ all_match = false
+ break
+ end
+ end
+ if all_match then
+ spans.cols = {}
+ for n, start in ipairs(spans.starts) do -- find the start and end columns
+ local stop = spans.stops[n]
+ local starts_at, stops_at
+ for o=1, #bounds.slices do
+ if bounds.slices[o].start == start then
+ starts_at = o
+ end
+ if bounds.slices[o].stop == stop then
+ stops_at = o
+ end
+ end
+ spans.cols[n] = 1 + stops_at - starts_at
+ end
+ multispans[nr-1] = spans
+ end
+ end
+ end
+
+ for nr, row in ipairs(raw) do
+ local newrow = {}
+ if p.st_headsep:match(row) then
+ newrow.separator = true
+ if nr > 1 and #raw > nr then -- Ends the header.
+ rows.has_head = true
+ newrow.end_head = true
+ end
+ elseif multispans[nr] then
+ local spans = multispans[nr]
+ for nc, span in ipairs(spans.cols) do
+ local this = {}
+ this.content = string.strip(row:sub(spans.starts[nc], spans.stops[nc]))
+ this.span = span
+ newrow[#newrow+1] = this
+ end
+ elseif multispans[nr-1] then -- some cells span columns
+ newrow.ignore = true
+ else
+ local nc = 1
+ repeat
+ local this = {}
+ this.content = string.strip(row:sub(bounds.slices[nc].start, bounds.slices[nc].stop - 1))
+ if bounds.starts[nc+1] then
+ -- Only spaces allowed between columns.
+ local between = s:sub(bounds.stops[nc], bounds.slices[nc+1].start)
+ if not match(p.space^1 * -P(1), between) then
+ -- This is probably too hard a step.
+ helpers.dbg_write("[sta-h] Please revise your table boundaries.")
+ os.exit(1)
+ end
+ end
+ newrow[nc] = this
+ nc = nc + 1
+ until nc > #bounds.slices
+ end
+ rows[nr] = newrow
+ end
+ return rows
end
return helpers
+
diff --git a/rst_parser.lua b/rst_parser.lua
index cc4304d..54c3719 100644
--- a/rst_parser.lua
+++ b/rst_parser.lua
@@ -55,7 +55,8 @@ tracklists.bullets.max = 0
tracklists.lastbullet = ""
tracklists.roman_cache = {} -- storing roman numerals that were already converted
tracklists.currentindent = "" -- used in definition lists and elsewhere
-tracklists.currentwidth = 0-- table layout
+tracklists.currentwidth = 0 -- table layout
+tracklists.currentlayout = {} -- table layout
local enclosed_mapping = {
["'"] = "'",
@@ -212,14 +213,122 @@ local parser = P{
-- Table block
--------------------------------------------------------------------------------
- table_block = V"grid_table"
- --+ V"simple_table"
+ table_block = V"simple_table"
+ + V"grid_table"
/ rst.table
,
+--------------------------------------------------------------------------------
+-- Simple tables
+--------------------------------------------------------------------------------
+
+ simple_table = Ct(V"st_first_row"
+ * V"st_other_rows")
+ --* V"blank_line"^1
+ * V"end_block"^1
+ / function (tab)
+ return rst.simple_table(helpers.table.simple(tab))
+ end
+ ,
+
+ st_first_row = V"st_setindent"
+ * C(V"st_setlayout")
+ * V"space"^0
+ * V"eol"
+ ,
+
+ st_setindent = Cmt(V"space"^0, function(s, i, indent)
+ warn("sta-i", "true", #indent, "set", i)
+ tracklists.currentindent = indent
+ return true
+ end)
+ ,
+
+ st_matchindent = Cmt(V"space"^0, function(s, i, indent)
+ warn("sta-m", tracklists.currentindent == indent, #indent, #tracklists.currentindent, i)
+ return tracklists.currentindent == indent
+ end)
+ ,
+
+ st_setlayout = Cmt((V"equals"^1) * (V"spaces" * V"equals"^1)^1, function(s, i, layout)
+ local tc = tracklists.currentlayout
+ warn("sta-l", #layout, "set", "", i)
+ tc.raw = layout
+ tc.bounds = help.get_st_boundaries(layout)
+ return true
+ end)
+ ,
+
+ st_other_rows = (V"st_content"^1 * V"st_separator")^1,
+
+ st_content = C(V"st_matchlayout"),
+
+ st_matchlayout = -#V"st_separator" * Cmt((1 - V"eol")^1, function (s, i, content)
+ -- Don't check for matching indent but if the rest is
+ -- fine then the line should be sane. This allows
+ -- cells starting with spaces.
+ content = content:sub(#tracklists.currentindent)
+ local tcb = tracklists.currentlayout.bounds
+ local n = 1
+ local spaces_only = P" "^1
+ while n < #tcb.slices do
+ local from = tcb.slices[n] .stop
+ local to = tcb.slices[n+1].start
+ --print(n, from, to, content)
+ local between = spaces_only:match(content, from)
+ if not between then -- Cell spanning more than one row.
+ -- pass
+ warn("sta-c", "span", from, to, i)
+ elseif not (between >= to) then
+ warn("sta-c", "false", from, to, i)
+ return false
+ end
+ n = n + 1
+ end
+ warn("sta-c", "true", #tcb.slices, "", i)
+ return true
+ end)
+ * V"eol"
+ ,
+
+ st_separator = V"st_matchindent"
+ * C(V"st_normal_sep" + V"st_colspan_sep")
+ * V"eol"
+ ,
+
+ st_normal_sep = Cmt((V"equals"^1) * (V"spaces" * V"equals"^1)^1, function(s, i, layout)
+ warn("sta-s", tracklists.currentlayout.raw == layout, #layout, #tracklists.currentlayout.raw, i)
+ return tracklists.currentlayout.raw == layout
+ end)
+ ,
+
+ st_colspan_sep = Cmt(V"dash"^1 * (V"spaces" * V"dash"^1)^0, function(s, i, layout)
+ local tcb = tracklists.currentlayout.bounds
+ local this = help.get_st_boundaries (layout)
+ local start_valid = false
+ for start, _ in next, this.starts do
+ if tcb.starts[start] then
+ start_valid = true
+ local stop_valid = false
+ for stop, _ in next, this.stops do
+ if tcb.stops[stop] then -- bingo
+ stop_valid = true
+ end
+ end
+ if not stop_valid then
+ warn("sta-x", stop_valid, #layout, #tracklists.currentlayout.raw, i)
+ return false
+ end
+ end
+ end
+ warn("sta-x", start_valid, #layout, #tracklists.currentlayout.raw, i)
+ return start_valid
+ end)
+ ,
+
--------------------------------------------------------------------------------
--- Grid table
+-- Grid tables
--------------------------------------------------------------------------------
grid_table = Ct(V"gt_first_row"
@@ -235,7 +344,6 @@ local parser = P{
* V"eol"
,
- --gt_setindent = Cg(V"space"^0, "tableindent"),
gt_setindent = Cmt(V"space"^0, function(s, i, indent)
warn("tab-i", true, #indent, "set", i)
tracklists.currentindent = indent
@@ -256,7 +364,6 @@ local parser = P{
* V"gt_body"
,
- --gt_matchindent = Cmt(V"space"^0 * Cb"tableindent", function (s, i, this, matchme)
gt_matchindent = Cmt(V"space"^0, function (s, i, this)
local matchme = tracklists.currentindent
warn("tab-m", "indent", #this == #matchme, #this, #matchme, i)
@@ -652,7 +759,7 @@ local parser = P{
end),
--bullet_stop =V"blank_line" * Cs(Cc("")) / rst.stopitemize,
- bullet_stop =V"endpar" * Cs(Cc("")) / rst.stopitemize,
+ bullet_stop =V"end_block" * Cs(Cc("")) / rst.stopitemize,
bullet_init = V"eol"^0 * V"bullet_first" * V"bullet_itemrest",
@@ -758,7 +865,7 @@ local parser = P{
transition = V"eol"^0
* V"transition_line"
- * V"endpar"
+ * V"end_block"
/rst.transition,
--------------------------------------------------------------------------------
@@ -808,7 +915,7 @@ local parser = P{
* C(1 - V"whitespace" - V"eol")^1)^0)
* V"eol" * #(1 - V"whitespace" - "eol")) / rst.joinindented
+ C((1 - V"eol")^1) * V"eol" * #(V"double_dot" + V"eol")
- + (1 - V"endpar")^0 * Cc("make me constant!"),
+ + (1 - V"end_block")^0 * Cc("make me constant!"),
target = Ct((V"target_name" * (V"space"^0 * V"eol" * V"target_name")^0)
* V"space"^0
@@ -824,7 +931,7 @@ local parser = P{
/ rst.target,
target_block = (V"anonymous_target" + V"target")^1
- * V"endpar",
+ * V"end_block",
--------------------------------------------------------------------------------
-- Paragraphs * Inline Markup
@@ -833,7 +940,8 @@ local parser = P{
paragraph = V"par_setindent"
* Ct(C((1 - V"eol")^1) * V"eol"
* (V"par_matchindent" * C((1 - V"eol")^1) * V"eol")^0)
- * V"blank_line"^1
+ --* V"blank_line"^1
+ * V"end_block"^1
/ rst.paragraph,
par_setindent = Cmt(V"space"^0, function (s, i, indent)
@@ -926,7 +1034,7 @@ local parser = P{
-- Terminal Symbols and Low-Level Elements
--------------------------------------------------------------------------------
- word = (1 - V"punctuation" - V"endpar" - V"spacing" - V"eol")^1, -- TODO : no punctuation (later)
+ word = (1 - V"punctuation" - V"end_block" - V"spacing" - V"eol")^1, -- TODO : no punctuation (later)
asterisk = P"*",
double_asterisk = V"asterisk" * V"asterisk",
@@ -1017,7 +1125,9 @@ local parser = P{
eol = P"\n",
eof = V"eol"^0 * -P(1),
- endpar = V"eol" * (V"blank_line"^1 + V"eof"),
+ end_block = V"blank_line"^1
+ + (V"whitespace"^0 * V"eol"
+ * (V"whitespace"^0 * V"eol")^0 * V"eof"),
-- diverse markup character sets
delimiters = P"‐" + P"‑" + P"‒" + P"–" + V"emdash" + V"space", -- inline markup