ltp/template.lua

changeset 3
b2df1b3f2c83
child 6
219d7a7304f8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ltp/template.lua	Sun Sep 13 22:22:47 2009 +0300
@@ -0,0 +1,192 @@
+--
+-- Copyright 2007-2008 Savarese Software Research Corporation.
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+--     http://www.savarese.com/software/ApacheLicense-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+
+local ltp = require('ltp.util')
+
+local function compile_template_to_table(result, data, start_lua, end_lua)
+  local LF, CR, EQ = 10, 13, 61
+  local i1, i2, i3
+
+  i3 = 1
+
+  repeat
+    i2, i1 = data:find(start_lua, i3, true)
+
+    if i2 then
+      if i3 < i2 then
+        table.insert(result, "table.insert(output,")
+        table.insert(result, string.format('%q', data:sub(i3, i2 - 1)))
+        table.insert(result, ");")
+      end
+
+      i1 = i1 + 2
+      i2, i3 = data:find(end_lua, i1, true)
+
+      if i2 then
+        if data:byte(i1-1) == EQ then
+          table.insert(result, "table.insert(output,")
+          table.insert(result, data:sub(i1, i2 - 1))
+          table.insert(result, ");")
+          i3 = i3 + 1
+        else
+          table.insert(result, data:sub(i1, i2 - 1))
+          i3 = i3 + 1
+          if data:byte(i3) == LF then
+            i3 = i3 + 1
+          elseif data:byte(i3) == CR and data:byte(i3+1) == LF then
+            i3 = i3 + 2
+          end
+        end
+      end
+    elseif i3 <= #data then
+      table.insert(result, "table.insert(output,")
+      table.insert(result, string.format('%q', data:sub(i3)))
+      table.insert(result, ");")
+    end
+  until not i2
+
+  return result
+end
+
+local function compile_template_as_function(data, start_lua, end_lua)
+  local result = { "return function(output) " }
+  table.insert(compile_template_to_table(result, data, start_lua, end_lua),
+               "end")
+  return table.concat(result)
+end
+
+local function compile_template(data, start_lua, end_lua)
+  return
+  table.concat(compile_template_to_table({ }, data, start_lua, end_lua))
+end
+
+local function load_template(data, start_lua, end_lua)
+  return
+  assert(loadstring(compile_template_as_function(data, start_lua, end_lua),
+                    "=(load)"))()
+end
+
+local function execute_template(template, environment, output)
+  setfenv(template, environment)(output)
+end
+
+local function basic_environment(merge_global, environment)
+  if not environment then
+    environment = { }
+  end
+
+  if merge_global then
+    ltp.merge_index(environment, _G)
+  else
+    environment.table = table
+  end
+
+  return environment
+end
+
+local function load_environment(env_files, merge_global)
+  local environment = nil
+
+  if env_files and #env_files > 0 then
+    for i = 1,#env_files,1 do
+      local efun = assert(loadfile(env_files[i]))
+
+      if i > 1 then
+        environment = ltp.merge_table(setfenv(efun, environment)(), environment)
+      else
+        environment = basic_environment(merge_global, efun())
+      end
+    end
+  else
+    environment = basic_environment(merge_global)
+  end
+
+  return environment
+end
+
+local function read_template(template)
+  return ((template == "-" and io.stdin:read("*a")) or ltp.read_all(template))
+end
+
+local function render_template(template_data, start_lua, end_lua, environment)
+  local rfun = load_template(template_data, start_lua, end_lua)
+  local output = { }
+  execute_template(rfun, environment, output)
+  return table.concat(output)
+end
+
+local function execute_env_code(env_code, environment)
+  for i = 1,#env_code do
+    local fun, emsg = loadstring(env_code[i])
+
+    if fun then
+      setfenv(fun, environment)()
+    else
+      error("error loading " .. env_code[i] .. "\n" .. emsg)
+    end
+  end
+end
+
+local function render(outfile, num_passes, template, merge_global,
+                      env_files, start_lua, end_lua, env_code)
+  local data = assert(read_template(template), "error reading " .. template)
+  local environment = load_environment(env_files, merge_global)
+
+  execute_env_code(env_code, environment)
+
+  if num_passes > 0 then
+    for i = 1,num_passes do
+      data = render_template(data, start_lua, end_lua, environment)
+    end
+  else
+    -- Prevent an infinite loop by capping expansion to 100 times.
+    num_passes = 1
+    repeat
+      data = render_template(data, start_lua, end_lua, environment)
+      num_passes = num_passes + 1
+    until data:find(start_lua, 1, true) == nil or num_passes >= 100
+  end
+
+  outfile:write(data);
+end
+
+local function compile_as_function(outfile, template, start_lua, end_lua)
+  local data = read_template(template)
+  outfile:write(compile_template_as_function(data, start_lua, end_lua))
+end
+
+local function compile(outfile, template, start_lua, end_lua)
+  local data = read_template(template)
+  outfile:write(compile_template(data, start_lua, end_lua))
+end
+
+return ltp.merge_table(
+  {
+    compile_template_to_table    = compile_template_to_table,
+    compile_template_as_function = compile_template_as_function,
+    compile_template             = compile_template,
+    load_template                = load_template,
+    execute_template             = execute_template,
+    basic_environment            = basic_environment,
+    load_environment             = load_environment,
+    render_template              = render_template,
+    execute_env_code             = execute_env_code,
+    render                       = render,
+    compile_as_function          = compile_as_function,
+    compile                      = compile
+  },
+  ltp
+)

mercurial