/* This is a copy of https://github.com/mfrigerio17/lua-template-engine/blob/master/src/template-text.lua */
static const char *MARPAESLIFLUA_TEMPLATE_ENGINE =
  "\n"
  "local function errHandler(e)\n"
  "  -- Try to get the number of the line of the template that caused the error,\n"
  "  -- parsing the text of the stacktrace. Note that the string here in the\n"
  "  -- matching pattern should correspond to whatever is generated in the\n"
  "  -- template_eval function, further down\n"
  "  local stacktrace = debug.traceback()\n"
  "  local linen = tonumber(stacktrace:match(\".-\\\"local text={}...\\\"]:(%d+).*\"))\n"
  "  return {\n"
  "    error = e,\n"
  "    lineNum = linen\n"
  "  }\n"
  "end\n"
  "\n"
  "--- Evaluate a chunk of code in a constrained environment.\n"
  "-- @param unsafe_code code string\n"
  "-- @param optional environment table.\n"
  "-- @return true or false depending on success\n"
  "-- @return function or error message\n"
  "local function eval_sandbox(unsafe_code, env)\n"
  "  local env = env or {}\n"
  "  local unsafe_fun, msg = load(unsafe_code, nil, 't', env)\n"
  "  if unsafe_fun==nil then\n"
  "    return false, {loadError=true, msg=msg}\n"
  "  end\n"
  "  return xpcall(unsafe_fun, errHandler)\n"
  "end\n"
  "\n"
  "local function lines(s)\n"
  "        if s:sub(-1)~=\"\\n\" then s=s..\"\\n\" end\n"
  "        return s:gmatch(\"(.-)\\n\")\n"
  "end\n"
  "\n"
  "--- Copy every string in the second argument into the first, prepending indentation.\n"
  "-- The first argument must be a table. The second argument is either a table\n"
  "-- itself (having strings as elements) or a function returning a factory of\n"
  "-- a suitable iterator; for example, a function returning 'ipairs(t)', where 't'\n"
  "-- is a table of strings, is a valid argument.\n"
  "local insertLines = function(text, lines, totIndent)\n"
  "  local factory = lines\n"
  "  if type(lines) == 'table' then\n"
  "    factory = function() return ipairs(lines) end\n"
  "  end\n"
  "  for i,line in factory() do\n"
  "    local lineadd = \"\"\n"
  "    if line ~= \"\" then\n"
  "      lineadd = totIndent .. line\n"
  "    end\n"
  "    table.insert(text, lineadd)\n"
  "  end\n"
  "end\n"
  "\n"
  "--- Decorates an existing string iteration, adding an optional prefix and suffix.\n"
  "-- The first argument must be a function returning an existing iterator\n"
  "-- generator, such as a 'ipairs'.\n"
  "-- The second and last argument are strings, both optional.\n"
  "--\n"
  "-- Sample usage:\n"
  "--   local t = {\"a\",\"b\",\"c\",\"d\"}\n"
  "--   for i,v in ipairs(t) do\n"
  "--     print(i,v)\n"
  "--   end\n"
  "--\n"
  "--   for i,v in lineDecorator( function() return ipairs(t) end, \"--- \", \" ###\") do\n"
  "--     print(i,v)\n"
  "--   end\n"
  "local lineDecorator = function(generator, prefix, suffix)\n"
  "  local opts = opts or {}\n"
  "  local prefix = prefix or \"\"\n"
  "  local suffix = suffix or \"\"\n"
  "  local iter, inv, ctrl = generator( )\n"
  "\n"
  "  return function()\n"
  "    local i, line = iter(inv, ctrl)\n"
  "    ctrl = i\n"
  "    local retline = \"\"\n"
  "    if line ~= nil then\n"
  "      if line ~= \"\" then\n"
  "        retline = prefix .. line .. suffix\n"
  "      end\n"
  "    end\n"
  "    return i, retline -- nil or \"\"\n"
  "  end\n"
  "end\n"
  "\n"
  "--- Evaluate the given text-template into a string.\n"
  "-- Regular text in the template is copied verbatim, while expressions in the\n"
  "-- form $(<var>) are replaced with the textual representation of <var>, which\n"
  "-- must be defined in the given environment.\n"
  "-- Finally, lines starting with @ are interpreted entirely as Lua code.\n"
  "--\n"
  "-- @param template the text-template, as a string\n"
  "-- @param env the environment for the evaluation of the expressions in the\n"
  "--        templates (if not given, 'table', 'pairs', 'ipairs' are added\n"
  "--        automatically to this enviroment)\n"
  "-- @param opts non-mandatory options\n"
  "--        - indent: number of blanks to be prepended before every output line;\n"
  "--          this applies to the whole template, relative indentation between\n"
  "--          different lines is preserved\n"
  "--        - xtendStyle: if true, variables are matched with this pattern \"«<var>»\"\n"
  "-- @return The text of the evaluated template; if the option 'returnTable' is\n"
  "--         set to true, though, the table with the sequence of lines of text is\n"
  "--         returned instead\n"
  "local function template_eval(template, env, opts)\n"
  "\n"
  "  local opts    = opts or {}\n"
  "  local indent  = string.format(\"%s\", string.rep(' ', (opts.indent or 0) ) )\n"
  "\n"
  "  -- Define the matching patter for the variables, depending on options.\n"
  "  -- The matching pattern reads in general as: <text><var><string position>\n"
  "  local varMatch = {\n"
  "    pattern = \"(.-)$(%b())()\",\n"
  "    extract = function(expr) return expr:sub(2,-2) end\n"
  "  }\n"
  "  if opts.xtendStyle then\n"
  "    varMatch.pattern = \"(.-)«(.-)»()\"\n"
  "    varMatch.extract = function(expr) return expr end\n"
  "  end\n"
  "\n"
  "  -- Generate a line of code for each line in the input template.\n"
  "  -- The lines of code are also strings; we add them in the 'chunk' table.\n"
  "  -- Every line is either the insertion in a table of a string, or a 1-to-1 copy\n"
  "  --  of the code inserted in the template via the '@' character.\n"
  "  local chunk = {\"local text={}\"}\n"
  "  local lineOfCode = nil\n"
  "  for line in lines(template) do\n"
  "    -- Look for a '@' ignoring blanks (%s) at the beginning of the line\n"
  "    -- If it's there, copy the string following the '@'\n"
  "    local s,e = line:find(\"^%s*@\")\n"
  "    if s then\n"
  "      lineOfCode = line:sub(e+1)\n"
  "    else\n"
  "      -- Look for the specials '${..}', which must be alone in the line\n"
  "      local tableIndent, tableVarName = line:match(\"^([%s]*)${(.-)}[%s]*\")\n"
  "      if tableVarName ~= nil then\n"
  "        -- Preserve the indentation used for the \"${..}\" in the original template.\n"
  "        -- \"Sum\" it to the global indentation passed here as an option.\n"
  "        local totIndent = string.format(\"%q\", indent .. tableIndent)\n"
  "        lineOfCode = \"__insertLines(text, \" .. tableVarName .. \", \" .. totIndent .. \")\"\n"
  "      else\n"
  "        -- Look for the template variables in the current line.\n"
  "        -- All the matches are stored as strings '\"<text>\" .. <variable>'\n"
  "        -- Note that <text> can be empty\n"
  "        local subexpr = {}\n"
  "        local lastindex = 1\n"
  "        local c = 1\n"
  "        for text, expr, index in line:gmatch(varMatch.pattern) do\n"
  "          subexpr[c] = string.format(\"%q .. %s\", text, varMatch.extract(expr))\n"
  "          lastindex = index\n"
  "          c = c + 1\n"
  "        end\n"
  "        -- Add the remaining part of the line (no further variable) - or the\n"
  "        -- entire line if no $() was found\n"
  "        subexpr[c] = string.format(\"%q\", line:sub(lastindex))\n"
  "\n"
  "        -- Concatenate the subexpressions into a single one, prepending the\n"
  "        -- indentation if it is not empty\n"
  "        local expression = table.concat(subexpr, ' .. ')\n"
  "        if expression~=\"\\\"\\\"\" and indent~=\"\" then\n"
  "          expression = string.format(\"%q\", indent) .. ' .. ' .. expression\n"
  "        end\n"
  "\n"
  "        lineOfCode = \"table.insert(text, \" .. expression .. \")\"\n"
  "      end\n"
  "    end\n"
  "    table.insert(chunk, lineOfCode)\n"
  "  end\n"
  "\n"
  "  local returnTable = opts.returnTable or false\n"
  "  if returnTable then\n"
  "    table.insert(chunk, \"return text\")\n"
  "  else\n"
  "    -- The last line of code performs string concatenation, so that the evaluation\n"
  "    -- of the code eventually leads to a string\n"
  "    table.insert(chunk, \"return table.concat(text, '\\\\n')\")\n"
  "  end\n"
  "  --print( table.concat(chunk, '\\n') )\n"
  "\n"
  "\n"
  "  env.table = (env.table or table)\n"
  "  env.pairs = (env.pairs or pairs)\n"
  "  env.ipairs = (env.ipairs or ipairs)\n"
  "  env.__insertLines = insertLines\n"
  "  local ok, ret = eval_sandbox(table.concat(chunk, '\\n'), env)\n"
  "  if not ok then\n"
  "    local errMessage = \"Error in template evaluation\" -- default, should be overwritten\n"
  "    if ret.loadError then\n"
  "      errMessage = \"Syntactic error in the loaded code: \" .. ret.msg\n"
  "    else\n"
  "      local linen = ret.lineNum or -1\n"
  "      local line = \"??\"\n"
  "      if linen ~= -1 then line = chunk[linen] end\n"
  "      local err1 = \"Template evaluation failed around this line:\\n\\t>>> \" .. line .. \" (line #\" .. linen .. \")\"\n"
  "      local err2 = \"Interpreter error: \" .. (tostring(ret.error) or \"\")\n"
  "      errMessage = err1 .. \"\\n\" .. err2\n"
  "    end\n"
  "    return false, errMessage\n"
  "  end\n"
  "  return ok, ret\n"
  "end\n"
  "\n"
  "return {\n"
  "  template_eval = template_eval,\n"
  "  lineDecorator = lineDecorator\n"
  "}\n";
