% an experiment, no module yet

\startluacode
local byte, format = string.byte, string.format

spreadsheets = { }

local mt = {
    __index = function(t,k)
        local v = { }
        setmetatable(v,mt)
        t[k] = v
        return v
    end,
}

function spreadsheets.reset()
    spreadsheets.data = { }
    setmetatable(spreadsheets.data,mt)
end

spreadsheets.reset()

-- I'll make a nice lpeg

local offset = byte("A") - 1

local function execute(r,c,str)
    str = string.gsub(str,"([A-Z])",function(s)
        return format("spreadsheets.data[%s]",byte(s)-offset)
    end)
    -- todo: error checking + report
    local result = loadstring("return ".. str)
    result = result and result() or 0
    spreadsheets.data[c][r] = result
    return result
end

function spreadsheets.set(r,c,str)
    execute(r,c,str)
end

function spreadsheets.get(r,c,str)
    local result = execute(r,c,str)
    if result then
        context(result)
    end
end
\stopluacode

\def\resetspreadsheet{\ctxlua{spreadsheets.reset()}}
\def\setspreadsheet#1{\ctxlua{spreadsheets.set(\number\tblrow+1,\number\tblcol,"#1")}}
\def\getspreadsheet#1{\ctxlua{spreadsheets.get(\number\tblrow+1,\number\tblcol,"#1")}}

% we need an everyTABLE

\let\set\setspreadsheet
\let\get\getspreadsheet

\starttext

\bTABLE[align=middle]
   \bTR
     \bTD \get{100} \eTD \bTD test \set{30} \eTD
   \eTR
   \bTR
     \bTD \get{20} \eTD \bTD \get{4+3} \eTD
   \eTR
   \bTR
     \bTD \get{A[1] + A[2]} \eTD
     \bTD \get{B[1] + B[2]} \eTD
   \eTR
   \bTR
     \bTD[nx=2] \bf \get{A[3] + B[3]} \eTD
   \eTR
\eTABLE

\def\startspreadsheet#1\stopspreadsheet
  {\resetspreadsheet
   \bTABLE#1\eTABLE}

\def\startrow#1\stoprow
  {\bTR#1\eTR}

\def\startcell#1\stopcell
  {\bTD\get{#1}\eTD}

\startspreadsheet
   \startrow
     \startcell 3 \stopcell
     \startcell 5 \stopcell
     \startcell A[1] + B[1] \stopcell
   \stoprow
\stopspreadsheet

\stoptext
